[Fact]
public void ClassifyConversion_01()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestExplicitLong1(new C0());
TestExplicitLong2(new C0());
}
public static long TestExplicitLong1(C0 x)
{
checked { return (long)x; }
}
public static long TestExplicitLong2(C0 y)
{
return checked( (long)y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
checked C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var int64 = ((IMethodSymbol)model.GetSymbolInfo(xNode.Parent).Symbol).ReturnType;
Assert.Equal("System.Int64", int64.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_CheckedExplicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_CheckedExplicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_CheckedExplicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_CheckedExplicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
}
[Fact]
public void ClassifyConversion_03()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestExplicitLong1(new C0());
TestExplicitLong2(new C0());
}
public static long TestExplicitLong1(C0 x)
{
checked { unchecked { return (long)x; }}
}
public static long TestExplicitLong2(C0 y)
{
checked { return unchecked( (long)y); }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var int64 = ((IMethodSymbol)model.GetSymbolInfo(xNode.Parent).Symbol).ReturnType;
Assert.Equal("System.Int64", int64.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_Explicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_Explicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_Explicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
// !!! Expected System.Int64 C0.op_Explicit(C0 x) !!!
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
}
[Fact]
public void GetSpeculativeSymbolInfo_01()
{
var source1 =
@"
public class C0
{
public static C0 operator checked -(C0 a)
{
System.Console.WriteLine(""checked C0"");
return a;
}
public static C0 operator -(C0 a)
{
System.Console.WriteLine(""regular C0"");
return a;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
Test1(new C0());
Test2(new C0());
}
public static C0 Test1(C0 x)
{
checked { return -x; }
}
public static C0 Test2(C0 y)
{
return checked( -y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
checked C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var xNodeToSpeculate = SyntaxFactory.ParseExpression("-x");
var yNodeToSpeculate = SyntaxFactory.ParseExpression("-y");
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(xNode.SpanStart, xNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
// !!! Expected C0 C0.op_CheckedUnaryNegation(C0 a) !!!
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(yNode.SpanStart, yNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
}
[Fact]
public void GetSpeculativeSymbolInfo_02()
{
var source1 =
@"
public class C0
{
public static C0 operator checked -(C0 a)
{
System.Console.WriteLine(""checked C0"");
return a;
}
public static C0 operator -(C0 a)
{
System.Console.WriteLine(""regular C0"");
return a;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
Test1(new C0());
Test2(new C0());
}
public static C0 Test1(C0 x)
{
checked { unchecked { return -x; } }
}
public static C0 Test2(C0 y)
{
checked { return unchecked( -y); }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var xNodeToSpeculate = SyntaxFactory.ParseExpression("-x");
var yNodeToSpeculate = SyntaxFactory.ParseExpression("-y");
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(xNode.SpanStart, xNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
// !!! Expected C0 C0.op_UnaryNegation(C0 a) !!!
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(yNode.SpanStart, yNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
}
Comments in the repro indicate unexpected behavior: