|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class SemanticModelGetSemanticInfoTests_LateBound : SemanticModelTestBase
{
[Fact]
public void ObjectCreation()
{
string sourceCode = @"
class C
{
public C(string x) {}
public C(int x) {}
public C(double x) {}
public void M(dynamic d)
{
/*<bind>*/new C(d);/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal("C", semanticInfo.Type.Name);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(3, semanticInfo.CandidateSymbols.Length);
Assert.Equal(3, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void ObjectCreation_ByRefDynamicArgument1()
{
string sourceCode = @"
class C
{
public C(out dynamic x, ref dynamic y) { }
public void M(dynamic d)
{
/*<bind>*/new C(out d, ref d);/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal("C", semanticInfo.Type.Name);
Assert.Equal("C..ctor(out dynamic x, ref dynamic y)", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason);
}
[Fact]
public void ObjectCreation_ByRefDynamicArgument2()
{
string sourceCode = @"
class C
{
public C(out dynamic x, dynamic y) {}
public void M(dynamic d)
{
/*<bind>*/new C(out d, d);/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal("C", semanticInfo.Type.Name);
Assert.Equal("C..ctor(out dynamic x, dynamic y)", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(1, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void ObjectCreation_ByRefDynamicArgument3()
{
string sourceCode = @"
class C
{
public C(out dynamic x, int y) {}
public C(out dynamic x, long y) {}
public void M(dynamic d)
{
/*<bind>*/new C(out d, d);/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal("C", semanticInfo.Type.Name);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal("C..ctor(out dynamic x, System.Int32 y)", semanticInfo.CandidateSymbols[0].ToTestDisplayString());
Assert.Equal("C..ctor(out dynamic x, System.Int64 y)", semanticInfo.CandidateSymbols[1].ToTestDisplayString());
Assert.Equal(2, semanticInfo.MethodGroup.Length);
Assert.Equal("C..ctor(out dynamic x, System.Int32 y)", semanticInfo.MethodGroup[0].ToTestDisplayString());
Assert.Equal("C..ctor(out dynamic x, System.Int64 y)", semanticInfo.MethodGroup[1].ToTestDisplayString());
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void DelegateInvocation()
{
string sourceCode = @"
class C
{
public void M()
{
dynamic d = null;
/*<bind>*/d()/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodInvocation_DynamicReceiver()
{
string sourceCode = @"
class C
{
public void M()
{
dynamic d = null;
/*<bind>*/ d.bar() /*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodInvocation_StaticReceiver()
{
string sourceCode = @"
class C
{
public void M()
{
dynamic d = null;
C s = null;
/*<bind>*/ s.bar(d) /*</bind>*/;
}
public void bar(int a)
{
}
public void bar(long a)
{
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal(2, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodInvocation_TypeReceiver_01()
{
string sourceCode1 = @"
class C
{
public static C Create(int arg) { return null; }
public void M(dynamic d)
{
/*<bind>*/C.Create(d);/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode1);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.Equal("C C.Create(System.Int32 arg)", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(1, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
string sourceCode2 = @"
class C
{
public static C Create(int arg) { return null; }
public void M(dynamic d)
{
/*<bind>*/C.Create/*</bind>*/(d);
}
}
";
semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode2);
Assert.Equal(1, semanticInfo.MethodGroup.Length);
}
[Fact]
public void MethodInvocation_TypeReceiver_02()
{
string sourceCode = @"
class C
{
public static C Create(int arg) { return null; }
public static C Create(long arg) { return null; }
public void M(dynamic d)
{
/*<bind>*/C.Create(d);/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal(2, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodGroup_EarlyBound()
{
string source = @"
using System.Collections.Generic;
class List : List<int>
{
public void Add(int x, string y)
{
/*<bind>*/Add/*</bind>*/(x);
}
}";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(source);
Assert.Null(semanticInfo.Type);
Assert.Equal("void System.Collections.Generic.List<System.Int32>.Add(System.Int32 item)", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(2, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodGroup_DynamicArg()
{
string source = @"
using System.Collections.Generic;
class List : List<int>
{
public void Add(dynamic x, string y)
{
/*<bind>*/Add/*</bind>*/(x);
}
public void Add(long y)
{
}
}";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(source);
Assert.Null(semanticInfo.Type);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal(3, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodInvocation_DynamicArg()
{
string source = @"
using System.Collections.Generic;
class List : List<int>
{
public void Add(dynamic x, string y)
{
/*<bind>*/Add(x)/*</bind>*/;
}
public void Add(long y)
{
}
}";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(source);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal(2, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MethodInvocation_StaticReceiver_ByRefDynamicArgument()
{
string sourceCode = @"
class C
{
public void M()
{
dynamic d = null;
C s = null;
/*<bind>*/ s.bar(ref d) /*</bind>*/;
}
public int bar(ref dynamic a)
{
return 1;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason);
Assert.Equal(SpecialType.System_Int32, semanticInfo.Type.SpecialType);
Assert.Equal(SpecialType.System_Int32, semanticInfo.ConvertedType.SpecialType);
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal("System.Int32 C.bar(ref dynamic a)", semanticInfo.Symbol.ToTestDisplayString());
}
[Fact, WorkItem(531141, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531141")]
public void MethodInvocation_StaticReceiver_IdentifierNameSyntax()
{
string sourceCode = @"
using System;
namespace Dynamic
{
class FunctionTestingWithOverloading
{
public dynamic OverloadedFunction(int d)
{
return d;
}
public dynamic OverloadedFunction(long d)
{
return d;
}
}
class Program
{
static void Main(string[] args)
{
FunctionTestingWithOverloading obj = new FunctionTestingWithOverloading();
dynamic valueToBePassed = ""Hello"";
dynamic result = obj./*<bind>*/OverloadedFunction/*</bind>*/(valueToBePassed);
Console.WriteLine(""Value from overloaded function is {0}"", result);
}
}
}
";
var semanticInfo = GetSemanticInfoForTest<IdentifierNameSyntax>(sourceCode);
Assert.Null(semanticInfo.Type);
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal("dynamic Dynamic.FunctionTestingWithOverloading.OverloadedFunction(System.Int32 d)", semanticInfo.CandidateSymbols[0].ToTestDisplayString());
Assert.Equal("dynamic Dynamic.FunctionTestingWithOverloading.OverloadedFunction(System.Int64 d)", semanticInfo.CandidateSymbols[1].ToTestDisplayString());
Assert.Null(semanticInfo.Symbol);
Assert.Equal(2, semanticInfo.MethodGroup.Length);
Assert.Equal("dynamic Dynamic.FunctionTestingWithOverloading.OverloadedFunction(System.Int32 d)", semanticInfo.MethodGroup[0].ToTestDisplayString());
Assert.Equal("dynamic Dynamic.FunctionTestingWithOverloading.OverloadedFunction(System.Int64 d)", semanticInfo.MethodGroup[1].ToTestDisplayString());
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void CollectionInitializer()
{
string sourceCode = @"
class C
{
public void M()
{
dynamic d = 0;
var l = new List<int>
{
/*<bind>*/{ d }/*</bind>*/
};
}
public void bar(int a)
{
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
}
[Fact]
public void ObjectInitializer()
{
string sourceCode = @"
class C
{
public dynamic Z;
public void M()
{
dynamic d = 0;
var c = new C
{
/*<bind>*/Z = d/*</bind>*/
};
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
// TODO: what about object initializers?
}
[Fact]
public void Indexer_StaticReceiver_01()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
C c = null;
var x = /*<bind>*/c[d]/*</bind>*/;
}
public int this[int a]
{
get { return 0; }
set { }
}
public int this[long a]
{
get { return 0; }
set { }
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(2, semanticInfo.CandidateSymbols.Length);
Assert.Equal("System.Int32 C.this[System.Int32 a] { get; set; }", semanticInfo.CandidateSymbols[0].ToTestDisplayString());
Assert.Equal("System.Int32 C.this[System.Int64 a] { get; set; }", semanticInfo.CandidateSymbols[1].ToTestDisplayString());
Assert.Null(semanticInfo.Symbol);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void Indexer_StaticReceiver_02()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
C c = null;
var x = /*<bind>*/c[d]/*</bind>*/;
}
public int this[int a]
{
get { return 0; }
set { }
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal("System.Int32 C.this[System.Int32 a] { get; set; }", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void Indexer_DynamicReceiver()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
C c = null;
var x = /*<bind>*/d[c]/*</bind>*/;
}
public int this[int a]
{
get { return 0; }
set { }
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void MemberAccess()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
var x = /*<bind>*/d.F/*</bind>*/;
}
public int F { get; set; }
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void UnaryOperators()
{
var operators = new[] { "~", "!", "-", "+", "++", "--" };
var operatorNames = new[] { WellKnownMemberNames.OnesComplementOperatorName,
WellKnownMemberNames.LogicalNotOperatorName,
WellKnownMemberNames.UnaryNegationOperatorName,
WellKnownMemberNames.UnaryPlusOperatorName,
WellKnownMemberNames.IncrementOperatorName,
WellKnownMemberNames.DecrementOperatorName };
for (int i = 0; i < operators.Length; i++)
{
var op = operators[i];
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
var x1 = /*<bind>*/" + op + @"d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal("dynamic dynamic." + operatorNames[i] + "(dynamic value)", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
}
[Fact]
public void Await()
{
string sourceCode = @"
class C
{
public async Task<dynamic> M()
{
dynamic d = null;
var x1 = /*<bind>*/await d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void BinaryOperators()
{
foreach (var op in new[] { "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "!=", "==", "^", "&", "|", "&&", "||" })
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
var x1 = /*<bind>*/d" + op + @"d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
if (op == "&&" || op == "||")
{
Assert.Null(semanticInfo.Symbol);
}
else
{
Assert.Equal("dynamic.operator " + op + "(dynamic, dynamic)", semanticInfo.Symbol.ToString());
}
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
}
[Fact]
public void NullCoalescing()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
var x1 = /*<bind>*/d ?? d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
// not a late bound operation
Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void ConditionalExpression_DynamicCondition()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
dynamic d = null;
var x1 = /*<bind>*/d ? d : d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void ConditionalExpression_StaticCondition()
{
string sourceCode = @"
class C
{
public void TestMeth()
{
bool s = true;
dynamic d = null;
var x1 = /*<bind>*/s ? d : d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Null(semanticInfo.Symbol);
Assert.Equal(CandidateReason.None, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
[Fact]
public void CompoundAssignment()
{
foreach (var op in new[] { "+=", "%=", "+=", "-=", "<<=", ">>=", "^=", "&=", "|=" })
{
string sourceCode = @"
class C
{
public void M()
{
dynamic d = null;
/*<bind>*/d" + op + @"d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.True(semanticInfo.Type.IsDynamic());
Assert.True(semanticInfo.ConvertedType.IsDynamic());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal("dynamic.operator " + op.Substring(0, op.Length - 1) + "(dynamic, dynamic)", semanticInfo.Symbol.ToString());
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
}
[Fact]
public void EventOperators()
{
foreach (var op in new[] { "+=", "-=" })
{
string sourceCode = @"
class C
{
public event System.Action E;
public void M()
{
dynamic d = null;
/*<bind>*/E" + op + @"d/*</bind>*/;
}
}
";
var semanticInfo = GetSemanticInfoForTest<ExpressionSyntax>(sourceCode);
Assert.Equal("System.Void", semanticInfo.Type.ToTestDisplayString());
Assert.Equal("System.Void", semanticInfo.ConvertedType.ToTestDisplayString());
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
Assert.Equal(op == "+=" ? "void C.E.add" : "void C.E.remove", semanticInfo.Symbol.ToTestDisplayString());
Assert.Equal(CandidateReason.LateBound, semanticInfo.CandidateReason);
Assert.Equal(0, semanticInfo.CandidateSymbols.Length);
Assert.Equal(0, semanticInfo.MethodGroup.Length);
Assert.False(semanticInfo.IsCompileTimeConstant);
}
}
}
}
|