|
// 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.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class SemanticTests : CSharpTestBase
{
[Fact]
public void PatternIndexAndRangeIndexersSpeculativeModel()
{
var comp = CreateCompilationWithIndexAndRange(@"
class C
{
int Length => 0;
int this[int i] => i;
char Slice(int i, int j) => 'a';
void M()
{
_ = this[^0];
_ = this[0..];
}
}");
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var root = tree.GetRoot();
var m = root.DescendantNodes().OfType<MethodDeclarationSyntax>().Single(decl => decl.Identifier.ValueText == "M");
var m2 = m.WithoutTrailingTrivia();
var accesses = m.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToList();
var indexerAccess = accesses[0];
model.TryGetSpeculativeSemanticModelForMethodBody(indexerAccess.SpanStart, m2, out var speculativeModel);
accesses = m2.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToList();
indexerAccess = accesses[0];
var typeInfo = speculativeModel.GetTypeInfo(indexerAccess);
Assert.Equal(SpecialType.System_Int32, typeInfo.Type.SpecialType);
indexerAccess = accesses[1];
typeInfo = speculativeModel.GetTypeInfo(indexerAccess);
Assert.Equal(SpecialType.System_Char, typeInfo.Type.SpecialType);
}
[Fact]
public void UnmanagedConstraintOnExtensionMethod()
{
var src = @"
public static class Ext
{
public static T GenericExtension<T>(ref this T self) where T : unmanaged
{
return self;
}
}
";
var src2 = @"
public class Program
{
public struct S<T> where T : unmanaged
{
public T t;
}
static void M<T>(S<T> s) where T : unmanaged
{
s.GenericExtension();
}
}";
var comp1 = CreateCompilation(src, parseOptions: TestOptions.Regular8);
var comp2 = CreateCompilation(src2, parseOptions: TestOptions.Regular8,
references: new[] { comp1.ToMetadataReference() });
comp2.VerifyDiagnostics();
Assert.NotNull(checkSymbolInfo(comp2).Symbol);
comp2 = CreateCompilation(src2, parseOptions: TestOptions.Regular7_3,
references: new[] { comp1.ToMetadataReference() });
comp2.VerifyDiagnostics(
// (11,11): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
// s.GenericExtension();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "GenericExtension").WithArguments("unmanaged constructed types", "8.0").WithLocation(11, 11));
var info = checkSymbolInfo(comp2);
Assert.Null(info.Symbol);
Assert.Equal(CandidateReason.OverloadResolutionFailure, info.CandidateReason);
static SymbolInfo checkSymbolInfo(CSharpCompilation comp)
{
SyntaxTree tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
SyntaxNode root = tree.GetRoot();
var invoke = root.DescendantNodes().OfType<MemberAccessExpressionSyntax>()
.Where(e => e.Name.ToString() == "GenericExtension").First();
return model.GetSymbolInfo(invoke);
}
}
[Fact]
public void PatternIndexAndRangeIndexers()
{
var comp = CreateCompilationWithIndexAndRange(@"
class C
{
int Length => 0;
int this[int i] => i;
char Slice(int i, int j) => 'a';
void M()
{
_ = this[^0];
_ = this[0..];
}
}");
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
var accesses = root.DescendantNodes().OfType<ElementAccessExpressionSyntax>().ToList();
var indexerAccess = accesses[0];
var typeInfo = model.GetTypeInfo(indexerAccess);
Assert.Equal(SpecialType.System_Int32, typeInfo.Type.SpecialType);
var symbolInfo = model.GetSymbolInfo(indexerAccess);
var propertySymbol = (IPropertySymbol)symbolInfo.Symbol;
Assert.NotNull(symbolInfo.Symbol);
Assert.True(propertySymbol.IsIndexer);
Assert.Empty(symbolInfo.CandidateSymbols);
indexerAccess = accesses[1];
typeInfo = model.GetTypeInfo(indexerAccess);
Assert.Equal(SpecialType.System_Char, typeInfo.Type.SpecialType);
symbolInfo = model.GetSymbolInfo(indexerAccess);
Assert.NotNull(symbolInfo.Symbol);
Assert.Equal(SymbolKind.Method, symbolInfo.Symbol.Kind);
Assert.Equal("Slice", symbolInfo.Symbol.Name);
Assert.Empty(symbolInfo.CandidateSymbols);
}
[Fact]
public void RefReassignSymbolInfo()
{
var comp = CreateCompilation(@"
class C
{
int f = 0;
void M(ref int rx)
{
(rx = ref f) = 0;
}
}");
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var root = tree.GetCompilationUnitRoot();
var assignment = root.DescendantNodes().OfType<ParenthesizedExpressionSyntax>().Single();
var model = comp.GetSemanticModel(tree);
Assert.Null(model.GetDeclaredSymbol(assignment));
var assignmentInfo = model.GetSymbolInfo(assignment);
Assert.Null(assignmentInfo.Symbol);
}
[Fact]
public void RefForSymbolInfo()
{
var comp = CreateCompilation(@"
class C
{
void M(int x)
{
for (ref readonly int rx = ref x;;)
{
if (rx == 0)
{
return;
}
}
}
}");
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var root = tree.GetCompilationUnitRoot();
var rx = root.DescendantNodes().OfType<IdentifierNameSyntax>().Last();
var model = comp.GetSemanticModel(tree);
var rxInfo = model.GetSymbolInfo(rx);
Assert.NotNull(rxInfo.Symbol);
var rxSymbol = Assert.IsAssignableFrom<ILocalSymbol>(rxInfo.Symbol);
Assert.True(rxSymbol.IsRef);
Assert.Equal(RefKind.RefReadOnly, rxSymbol.RefKind);
var rxDecl = root.DescendantNodes().OfType<ForStatementSyntax>().Single().Declaration;
Assert.Same(model.GetDeclaredSymbol(rxDecl.Variables.Single()), rxSymbol);
}
[Fact]
public void RefForEachSymbolInfo()
{
var comp = CreateCompilationWithMscorlibAndSpan(@"
using System;
class C
{
void M(Span<int> span)
{
foreach (ref readonly int rx in span)
{
if (rx == 0)
{
return;
}
}
}
}");
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var root = tree.GetCompilationUnitRoot();
var rx = root.DescendantNodes().OfType<IdentifierNameSyntax>().Last();
var model = comp.GetSemanticModel(tree);
var rxInfo = model.GetSymbolInfo(rx);
Assert.NotNull(rxInfo.Symbol);
var rxSymbol = Assert.IsAssignableFrom<ILocalSymbol>(rxInfo.Symbol);
Assert.True(rxSymbol.IsRef);
Assert.Equal(RefKind.RefReadOnly, rxSymbol.RefKind);
var rxDecl = root.DescendantNodes().OfType<ForEachStatementSyntax>().Single();
Assert.Same(model.GetDeclaredSymbol(rxDecl), rxSymbol);
}
[Fact]
public void LocalSymbolsAreEquivalentAcrossSemanticModelsFromTheSameCompilation()
{
var text = @"public class C { public void M() { int x = 10; } }";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model1 = comp.GetSemanticModel(tree);
var model2 = comp.GetSemanticModel(tree);
Assert.NotEqual(model1, model2);
var vardecl = tree.GetCompilationUnitRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().First();
var symbol1 = model1.GetDeclaredSymbol(vardecl);
var symbol2 = model2.GetDeclaredSymbol(vardecl);
Assert.NotSame(symbol1, symbol2);
Assert.Equal(symbol1, symbol2);
}
[Fact]
public void LocalSymbolsAreDifferentAcrossSemanticModelsFromDifferentCompilations()
{
var text = @"public class C { public void M() { int x = 10; } }";
var tree = Parse(text);
var comp1 = CreateCompilation(tree);
var comp2 = CreateCompilation(tree);
var model1 = comp1.GetSemanticModel(tree);
var model2 = comp2.GetSemanticModel(tree);
Assert.NotEqual(model1, model2);
var vardecl = tree.GetCompilationUnitRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().First();
var symbol1 = model1.GetDeclaredSymbol(vardecl);
var symbol2 = model2.GetDeclaredSymbol(vardecl);
Assert.NotSame(symbol1, symbol2);
Assert.NotEqual(symbol1, symbol2);
}
[Fact]
public void RangeVariableSymbolsAreEquivalentAcrossSemanticModelsFromTheSameCompilation()
{
var text = @"using System.Linq; public class C { public void M() { var q = from c in string.Empty select c; } }";
var tree = Parse(text);
var comp = CreateCompilationWithMscorlib40AndSystemCore(new[] { tree });
var model1 = comp.GetSemanticModel(tree);
var model2 = comp.GetSemanticModel(tree);
Assert.NotEqual(model1, model2);
var vardecl = tree.GetCompilationUnitRoot().DescendantNodes().OfType<QueryClauseSyntax>().First();
var symbol1 = model1.GetDeclaredSymbol(vardecl);
var symbol2 = model2.GetDeclaredSymbol(vardecl);
Assert.NotSame(symbol1, symbol2);
Assert.Equal(symbol1, symbol2);
}
[Fact]
public void RangeVariableSymbolsAreDifferentAcrossSemanticModelsFromDifferentCompilations()
{
var text = @"using System.Linq; public class C { public void M() { var q = from c in string.Empty select c; } }";
var tree = Parse(text);
var comp1 = CreateCompilationWithMscorlib40AndSystemCore(new[] { tree });
var comp2 = CreateCompilationWithMscorlib40AndSystemCore(new[] { tree });
var model1 = comp1.GetSemanticModel(tree);
var model2 = comp2.GetSemanticModel(tree);
Assert.NotEqual(model1, model2);
var vardecl = tree.GetCompilationUnitRoot().DescendantNodes().OfType<QueryClauseSyntax>().First();
var symbol1 = model1.GetDeclaredSymbol(vardecl);
var symbol2 = model2.GetDeclaredSymbol(vardecl);
Assert.NotSame(symbol1, symbol2);
Assert.NotEqual(symbol1, symbol2);
}
[Fact]
public void LabelSymbolsAreEquivalentAcrossSemanticModelsFromSameCompilation()
{
var text = @"public class C { public void M() { label: goto label; } }";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model1 = comp.GetSemanticModel(tree);
var model2 = comp.GetSemanticModel(tree);
Assert.NotEqual(model1, model2);
var statement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<GotoStatementSyntax>().First();
var symbol1 = model1.GetSymbolInfo(statement.Expression).Symbol;
var symbol2 = model2.GetSymbolInfo(statement.Expression).Symbol;
Assert.False(ReferenceEquals(symbol1, symbol2));
Assert.Equal(symbol1, symbol2);
}
[Fact]
public void LambdaParameterSymbolsAreEquivalentAcrossSemanticModelsFromSameCompilation()
{
var text = @"using System; public class C { public void M() { Func<int,int> f = (p) => p; } }";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model1 = comp.GetSemanticModel(tree);
var model2 = comp.GetSemanticModel(tree);
Assert.NotEqual(model1, model2);
var paramdecl = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().First();
var symbol1 = model1.GetDeclaredSymbol(paramdecl);
var symbol2 = model2.GetDeclaredSymbol(paramdecl);
Assert.NotSame(symbol1, symbol2);
Assert.Equal(symbol1.ContainingSymbol, symbol2.ContainingSymbol);
Assert.Equal(symbol1, symbol2);
}
[Fact]
public void LambdaParameterSymbolsAreDifferentAcrossSemanticModelsFromDifferentCompilations()
{
var text = @"using System; public class C { public void M() { Func<int,int> f = (p) => p; } }";
var tree1 = Parse(text);
var tree2 = Parse(text);
var comp1 = CreateCompilation(tree1);
var comp2 = CreateCompilation(tree2);
var model1 = comp1.GetSemanticModel(tree1);
var model2 = comp2.GetSemanticModel(tree2);
Assert.NotEqual(model1, model2);
var paramdecl1 = tree1.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().First();
var symbol1 = model1.GetDeclaredSymbol(paramdecl1);
var paramdecl2 = tree2.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().First();
var symbol2 = model2.GetDeclaredSymbol(paramdecl2);
Assert.NotSame(symbol1, symbol2);
Assert.NotEqual(symbol1.ContainingSymbol, symbol2.ContainingSymbol);
Assert.NotEqual(symbol1, symbol2);
}
[WorkItem(539740, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539740")]
[Fact]
public void NamespaceWithoutName()
{
var text = "namespace";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
comp.VerifyDiagnostics(
// (1,10): error CS1001: Identifier expected
// namespace
Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 10),
// (1,10): error CS1514: { expected
// namespace
Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 10),
// (1,10): error CS1513: } expected
// namespace
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 10));
var nsArray = tree.GetCompilationUnitRoot().DescendantNodes().Where(node => node.IsKind(SyntaxKind.NamespaceDeclaration)).ToArray();
Assert.Equal(1, nsArray.Length);
var nsSyntax = nsArray[0] as NamespaceDeclarationSyntax;
var symbol = model.GetDeclaredSymbol(nsSyntax);
Assert.Equal(string.Empty, symbol.Name);
}
[WorkItem(539740, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539740")]
[Fact]
public void FileScopedNamespaceWithoutName()
{
var text = "namespace;";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
comp.VerifyDiagnostics(
// (1,10): error CS1001: Identifier expected
// namespace;
Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 10));
var nsArray = tree.GetCompilationUnitRoot().DescendantNodes().Where(node => node.IsKind(SyntaxKind.FileScopedNamespaceDeclaration)).ToArray();
Assert.Equal(1, nsArray.Length);
var nsSyntax = nsArray[0] as FileScopedNamespaceDeclarationSyntax;
var symbol = model.GetDeclaredSymbol(nsSyntax);
Assert.Equal(string.Empty, symbol.Name);
}
[Fact]
public void LazyBoundUsings1()
{
var text =
@"
// Peter Golde[7/19/2010]: I managed to construct the following interesting example today,
// which Dev10 does compile. Interestingly, the resolution of one ""using"" can depend
// on the resolution of another ""using"" later in the same namespace.
using K = A.Q;
using L = B.R;
class B
{
public class R
{
public class Q
{
public class S : K { }
}
}
}
class A : L
{
public K.S v = null;
}
";
var comp = CreateCompilation(text);
var global = comp.GlobalNamespace;
var a = global.GetTypeMembers("A", 0).Single();
var abase = a.BaseType();
Assert.Equal("B.R", abase.ToTestDisplayString());
var b = global.GetTypeMembers("B", 0).Single();
var r = b.GetTypeMembers("R", 0).Single();
var q = r.GetTypeMembers("Q", 0).Single();
var v = a.GetMembers("v").Single() as FieldSymbol;
var s = v.Type;
Assert.Equal("B.R.Q.S", s.ToTestDisplayString());
var sbase = s.BaseType();
Assert.Equal("B.R.Q", sbase.ToTestDisplayString());
}
[Fact]
public void Diagnostics1()
{
var text =
@"
class A : A {}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var errs = comp.GetSemanticModel(tree).GetDeclarationDiagnostics();
Assert.Equal(1, errs.Count());
}
[Fact]
public void DiagnosticsInOneTree()
{
var partial1 =
@"
partial class A
{
void goo() { int x = y; }
}
class C : B {}
";
var partial2 =
@"
partial class A
{
int q; //an unused field in a partial type
void bar() { int x = z; }
}
class B : NonExistent {}
";
var partial1Tree = Parse(partial1);
var partial2Tree = Parse(partial2);
var comp = CreateCompilation(new SyntaxTree[] { partial1Tree, partial2Tree });
var errs = comp.GetSemanticModel(partial1Tree).GetDiagnostics();
Assert.Equal(1, errs.Count());
}
[Fact]
public void Bindings1()
{
var text =
@"
class B : A {}
class A {}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var bdecl = tree.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var bbase = bdecl.BaseList.Types[0].Type as TypeSyntax;
var model = comp.GetSemanticModel(tree);
var info = model.GetSymbolInfo(bbase);
Assert.NotNull(info.Symbol);
var a = comp.GlobalNamespace.GetTypeMembers("A", 0).Single().ISymbol;
Assert.Equal(a, info.Symbol);
Assert.Equal(a, model.GetTypeInfo(bbase).Type);
}
[Fact]
public void BaseScope1()
{
// ensure the base clause is not bound in the scope of the class
var text =
@"
public class C : B {}
public class A {
public class B {}
}
public class B : A {}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var cdecl = tree.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var cbase = cdecl.BaseList.Types[0].Type as TypeSyntax;
var model = comp.GetSemanticModel(tree);
var info = model.GetSymbolInfo(cbase);
Assert.NotNull(info.Symbol);
var b = comp.GlobalNamespace.GetTypeMembers("B", 0).Single().ISymbol;
Assert.Equal(b, info.Symbol);
Assert.Equal(b, model.GetTypeInfo(cbase).Type);
}
[Fact]
public void BaseScope2()
{
// ensure type parameters are in scope in the base clause
var text =
@"
public class C<T> : A<T> { }
public class A<T> : B { }
public class B {
public class T { }
}
";
var tree = Parse(text);
var comp = (Compilation)CreateCompilation(tree);
var cdecl = tree.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var cbase = cdecl.BaseList.Types[0].Type as TypeSyntax;
var model = comp.GetSemanticModel(tree);
var info = model.GetSymbolInfo(cbase);
Assert.NotNull(info.Symbol);
var cbasetype = info.Symbol as INamedTypeSymbol;
var c = comp.GlobalNamespace.GetTypeMembers("C", 1).Single();
Assert.Equal(c.BaseType, cbasetype);
}
[Fact]
public void Bindings2()
{
var text =
@"
class B<T> : A<T> {}
class A<T> {}
";
var tree = Parse(text);
var comp = (Compilation)CreateCompilation(tree);
var bdecl = tree.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var bbase = bdecl.BaseList.Types[0].Type as TypeSyntax; // A<T>
var model = comp.GetSemanticModel(tree);
var info = model.GetSymbolInfo(bbase);
Assert.NotNull(info.Symbol);
var at2 = info.Symbol as INamedTypeSymbol;
Assert.Equal(at2, model.GetTypeInfo(bbase).Type);
var a = comp.GlobalNamespace.GetTypeMembers("A", 1).Single();
var at = a.TypeParameters.First();
var b = comp.GlobalNamespace.GetTypeMembers("B", 1).Single();
var bt = b.TypeParameters.First();
Assert.Equal(a.OriginalDefinition, at2.OriginalDefinition);
Assert.Equal(bt, at2.TypeArguments.First());
}
[Fact]
public void Bindings3()
{
var text =
@"using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static Program Field;
}";
var tree1 = Parse(text);
var compilation = CreateCompilation(tree1);
var tree2 = Parse(text);
var classProgram = tree2.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var staticProgramField = classProgram.Members[0] as FieldDeclarationSyntax;
var program = staticProgramField.Declaration.Type;
var model = compilation.GetSemanticModel(tree1);
Assert.Throws<ArgumentException>(() =>
{
// tree2 not in the compilation
var lookup = model.GetSymbolInfo(program);
});
}
[Fact]
public void Bindings4()
{
var text =
@"using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
Program p;
static void Main(string[] args)
{
}
}";
var tree1 = Parse(text);
var compilation = (Compilation)CreateCompilation(tree1);
var decl = tree1.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var field = decl.Members[0] as FieldDeclarationSyntax;
var type = field.Declaration.Type;
var model = compilation.GetSemanticModel(tree1);
var info = model.GetSymbolInfo(type);
Assert.Equal(compilation.GlobalNamespace.GetTypeMembers("Program", 0).Single(), info.Symbol);
}
[Fact]
public void Bindings5()
{
var text =
@"using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
}
}";
var tree1 = Parse(text);
var tree2 = Parse(text);
var compilation = (Compilation)CreateCompilation(new SyntaxTree[] { tree1, tree2 });
var decl = tree1.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var method = decl.Members[0] as MethodDeclarationSyntax;
var type = method.ParameterList.Parameters[0].Type;
var model = compilation.GetSemanticModel(tree1);
var info = model.GetSymbolInfo(type);
Assert.Equal(compilation.GetSpecialType(SpecialType.System_String), (info.Symbol as IArrayTypeSymbol).ElementType);
}
[Fact]
public void Speculative1()
{
var text =
@"
class B {
object x;
}
class A {}
";
var tree = Parse(text);
var comp = (Compilation)CreateCompilation(tree);
var bdecl = tree.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var xdecl = bdecl.Members[0] as FieldDeclarationSyntax;
var model = comp.GetSemanticModel(tree);
TypeSyntax speculate = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier("A"));
var symbolInfo = model.GetSpeculativeSymbolInfo(xdecl.SpanStart, speculate, SpeculativeBindingOption.BindAsTypeOrNamespace);
var lookup = symbolInfo.Symbol as ITypeSymbol;
Assert.NotNull(lookup);
var a = comp.GlobalNamespace.GetTypeMembers("A", 0).Single();
Assert.Equal(a, lookup);
}
[Fact]
public void GetType1()
{
var text =
@"
class A {
class B {}
}
";
var tree = Parse(text);
var comp = (Compilation)CreateCompilation(tree);
var adecl = tree.GetCompilationUnitRoot().Members[0] as TypeDeclarationSyntax;
var bdecl = adecl.Members[0] as TypeDeclarationSyntax;
var model = comp.GetSemanticModel(tree);
var a1 = model.GetDeclaredSymbol(adecl);
var b1 = model.GetDeclaredSymbol(bdecl);
var global = comp.GlobalNamespace;
var a2 = global.GetTypeMembers("A", 0).Single();
var b2 = a2.GetTypeMembers("B", 0).Single();
Assert.Equal(a2, a1);
Assert.Equal(b2, b1);
}
[Fact]
public void DottedName()
{
var text =
@"
class Main {
A.B x; // this refers to the B within A.
}
class A {
public class B {}
}
class B {}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = (CSharpSemanticModel)comp.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
var mainDecl = root.Members[0] as TypeDeclarationSyntax;
var mainType = model.GetDeclaredSymbol(mainDecl);
var aDecl = root.Members[1] as TypeDeclarationSyntax;
var aType = model.GetDeclaredSymbol(aDecl);
var abDecl = aDecl.Members[0] as TypeDeclarationSyntax;
var abType = model.GetDeclaredSymbol(abDecl);
var bDecl = root.Members[2] as TypeDeclarationSyntax;
var bType = model.GetDeclaredSymbol(bDecl);
var xDecl = mainDecl.Members[0] as FieldDeclarationSyntax;
var xSym = mainType.GetMembers("x").Single() as IFieldSymbol;
Assert.Equal<ISymbol>(abType, xSym.Type);
var info = model.GetSymbolInfo((xDecl.Declaration.Type as QualifiedNameSyntax).Right);
Assert.Equal(abType, info.Symbol);
}
[Fact]
public void AliasQualifiedName()
{
var text =
@"
class B {}
namespace N {
class C : global::B {}
class B {}
}
";
var tree = Parse(text);
var comp = (Compilation)CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
var nDecl = root.Members[0] as NamespaceDeclarationSyntax;
var n2Decl = root.Members[1] as NamespaceDeclarationSyntax;
var cDecl = n2Decl.Members[0] as TypeDeclarationSyntax;
var cBase = (cDecl.BaseList.Types[0].Type as AliasQualifiedNameSyntax).Name;
var cBaseType = model.GetSymbolInfo(cBase).Symbol;
var bOuter = comp.GlobalNamespace.GetTypeMembers("B", 0).Single();
var bInner = (comp.GlobalNamespace.GetMembers("N").Single() as INamespaceSymbol).GetTypeMembers("B", 0).Single();
Assert.Equal(bOuter, cBaseType);
}
[Fact, WorkItem(528655, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528655")]
public void ErrorSymbolForInvalidCode()
{
var text = @"
public class A
{
int goo { void goo() {} } // Error
static int Main() { return 1; }
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var mems = comp.SourceModule.GlobalNamespace.GetMembers();
var typeA = mems.Where(s => s.Name == "A").Select(s => s);
Assert.Equal(1, typeA.Count());
var invalid = mems.Where(s => s.Name == WellKnownMemberNames.TopLevelStatementsEntryPointTypeName).Select(s => s);
Assert.Equal(1, invalid.Count());
}
[Fact, WorkItem(543225, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543225"), WorkItem(529057, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529057")]
public void MergePartialMethodAndParameterSymbols()
{
var text = @"
using System;
partial class PC
{
partial void PM(int pp);
}
partial class PC
{
partial void PM(int pp) {}
}
";
var tree = Parse(text);
var comp = (Compilation)CreateCompilation(tree);
var pTypeSym = comp.SourceModule.GlobalNamespace.GetTypeMembers("PC").Single();
var pMethodSym = pTypeSym.GetMembers("PM").Single();
var model = (CSharpSemanticModel)comp.GetSemanticModel(tree);
var pType01 = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().First();
var pType02 = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Last();
Assert.NotEqual(pType01, pType02);
var ptSym01 = model.GetDeclaredSymbol(pType01);
var ptSym02 = model.GetDeclaredSymbol(pType02);
// same partial type symbol
Assert.Same(ptSym01, ptSym02);
Assert.Equal(2, ptSym01.Locations.Length);
var pMethod01 = tree.GetCompilationUnitRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var pMethod02 = tree.GetCompilationUnitRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Last();
Assert.NotEqual(pMethod01, pMethod02);
var pmSym01 = model.GetDeclaredSymbol(pMethod01);
var pmSym02 = model.GetDeclaredSymbol(pMethod02);
// different partial method symbols:(
Assert.NotSame(pmSym01, pmSym02);
// the declaration one is what one can get from GetMembers()
Assert.Same(pMethodSym, pmSym01);
// with decl|impl point to each other
Assert.Null(pmSym01.PartialDefinitionPart);
Assert.Same(pmSym02, pmSym01.PartialImplementationPart);
Assert.Same(pmSym01, pmSym02.PartialDefinitionPart);
Assert.Null(pmSym02.PartialImplementationPart);
var pParam01 = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().First();
var pParam02 = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().Last();
Assert.NotEqual(pParam01, pParam02);
var ppSym01 = model.GetDeclaredSymbol(pParam01);
var ppSym02 = model.GetDeclaredSymbol(pParam02);
Assert.NotSame(ppSym01, ppSym02);
Assert.Equal(1, ppSym01.Locations.Length);
Assert.Equal(1, ppSym02.Locations.Length);
}
[Fact, WorkItem(544221, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544221")]
public void GetTypeInfoForOptionalParameterDefaultValueInDelegate()
{
var text = @"
using System;
class Test
{
public delegate void DGoo(byte i = 1);
protected internal void MGoo(sbyte j = 2) { }
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
var exprs = root.DescendantNodes().OfType<LiteralExpressionSyntax>().ToArray();
Assert.Equal(2, exprs.Length);
var type1 = model.GetTypeInfo(exprs[0]);
var type2 = model.GetTypeInfo(exprs[1]);
Assert.NotNull(type1.Type);
Assert.Equal("System.Int32", type1.Type.ToTestDisplayString());
Assert.NotNull(type2.Type);
Assert.Equal("System.Int32", type2.Type.ToTestDisplayString());
}
[Fact, WorkItem(544231, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544231")]
public void GetDeclSymbolForParameterOfPartialMethod()
{
var text1 = @"
using System;
partial class Partial001
{
static partial void Goo(ulong x);
}
";
var text2 = @"
using System;
partial class Partial001
{
static partial void Goo(ulong x) { }
static int Main() { return 1; }
}
";
var tree1 = Parse(text1);
var tree2 = Parse(text2);
var comp = CreateCompilation(new[] { tree1, tree2 });
var model1 = comp.GetSemanticModel(tree1);
var model2 = comp.GetSemanticModel(tree2);
var root1 = tree1.GetCompilationUnitRoot();
var root2 = tree1.GetCompilationUnitRoot();
var para1 = tree1.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().First();
var para2 = tree2.GetCompilationUnitRoot().DescendantNodes().OfType<ParameterSyntax>().First();
var sym1 = model1.GetDeclaredSymbol(para1);
var sym2 = model2.GetDeclaredSymbol(para2);
Assert.NotNull(sym1);
Assert.NotNull(sym2);
Assert.Equal("System.UInt64 x", sym1.ToTestDisplayString());
Assert.Equal("System.UInt64 x", sym2.ToTestDisplayString());
Assert.NotEqual(sym1.Locations[0], sym2.Locations[0]);
}
[Fact, WorkItem(544473, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544473")]
public void GetDeclSymbolForTypeParameterOfPartialMethod()
{
var text1 = @"
using System;
partial class Partial001
{
static partial void Goo<T>(T x);
}
";
var text2 = @"
using System;
partial class Partial001
{
static partial void Goo<T>(T x) { }
static int Main() { return 1; }
}
";
var tree1 = Parse(text1);
var tree2 = Parse(text2);
var comp = CreateCompilation(new List<SyntaxTree> { tree1, tree2 });
var model1 = comp.GetSemanticModel(tree1);
var model2 = comp.GetSemanticModel(tree2);
var root1 = tree1.GetCompilationUnitRoot();
var root2 = tree1.GetCompilationUnitRoot();
var para1 = tree1.GetCompilationUnitRoot().DescendantNodes().OfType<TypeParameterSyntax>().First();
var para2 = tree2.GetCompilationUnitRoot().DescendantNodes().OfType<TypeParameterSyntax>().First();
var sym1 = model1.GetDeclaredSymbol(para1);
var sym2 = model2.GetDeclaredSymbol(para2);
Assert.NotNull(sym1);
Assert.NotNull(sym2);
Assert.Equal("T", sym1.ToTestDisplayString());
Assert.Equal("T", sym2.ToTestDisplayString());
Assert.NotEqual(sym1.Locations[0], sym2.Locations[0]);
}
[Fact]
public void GetDeclaredSymbolForAnonymousTypeProperty01()
{
var text = @"
using System;
struct AnonTypeTest
{
static long Prop
{
get
{
short @short = -1;
var anonType = new { id = 123, @do = ""QC"", @short, Prop };
return anonType.id + anonType.@short;
}
}
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var anonProps = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AnonymousObjectMemberDeclaratorSyntax>();
Assert.Equal(4, anonProps.Count());
var symList = from ap in anonProps
let apsym = model.GetDeclaredSymbol(ap)
orderby apsym.Name
select apsym.Name;
var results = string.Join(", ", symList);
Assert.Equal("do, id, Prop, short", results);
}
[Fact]
public void GetDeclaredSymbolForAnonymousTypeProperty02()
{
var text = @"
using System;
class AnonTypeTest
{
long field = 111;
void M(byte p1, ref sbyte p2, out string p3, params string[] ary)
{
ulong local = 12345;
var anonType = new { local, this.field, p1, p2, ary };
p3 = anonType.ary.Length > 0 ? anonType.ary[0] : """";
}
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var anonProps = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AnonymousObjectMemberDeclaratorSyntax>();
Assert.Equal(5, anonProps.Count());
var symList = from ap in anonProps
let apsym = model.GetDeclaredSymbol(ap)
orderby apsym.Name
select apsym.Name;
var results = string.Join(", ", symList);
Assert.Equal("ary, field, local, p1, p2", results);
}
[Fact]
public void GetDeclaredSymbolForAnonymousTypeProperty03()
{
var text = @"
using System;
enum E { a, b, c }
class Base
{
protected E baseField = E.b;
protected virtual Base BaseProp { get { return this; } }
public Func<string, char> deleField;
}
class AnonTypeTest : Base
{
protected override Base BaseProp { get { return null; } }
char this[string @string]
{
get
{
var anonType = new { id = deleField, base.BaseProp, base.baseField, ret = @string };
return anonType.id(anonType.ret);
}
}
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var anonProps = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AnonymousObjectMemberDeclaratorSyntax>();
Assert.Equal(4, anonProps.Count());
var symList = from ap in anonProps
let apsym = model.GetDeclaredSymbol(ap)
orderby apsym.Name
select apsym.Name;
var results = string.Join(", ", symList);
Assert.Equal("baseField, BaseProp, id, ret", results);
}
[Fact]
public void GetDeclaredSymbolForAnonymousTypeProperty04()
{
var text = @"
using System;
enum E { a, b, c }
struct S
{
public static E sField;
public interface IGoo { }
public IGoo GetGoo { get; set; }
public IGoo GetGoo2() { return null; }
}
class AnonTypeTest
{
event Action<ushort> Eve
{
add
{
var anonType = new { a1 = new { S.sField, igoo = new { new S().GetGoo } } };
}
remove
{
var anonType = new { a1 = new { a2 = new { a2 = S.sField, a3 = new { a3 = new S().GetGoo2() } } } };
}
}
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var anonProps = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AnonymousObjectMemberDeclaratorSyntax>();
Assert.Equal(9, anonProps.Count());
var symList = from ap in anonProps
let apsym = model.GetDeclaredSymbol(ap)
orderby apsym.Name
select apsym.Name;
var results = string.Join(", ", symList);
Assert.Equal("a1, a1, a2, a2, a3, a3, GetGoo, igoo, sField", results);
}
[Fact(), WorkItem(542861, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542861"), WorkItem(529673, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529673")]
public void GetSymbolInfoForAccessorParameters()
{
var text = @"
using System;
public class Test
{
object[] _Items = new object[3];
public object this[int index]
{
get
{
return _Items[index];
}
set
{
_Items[index] = value;
}
}
}
";
var tree = Parse(text);
var comp = CreateCompilation(tree);
var model = comp.GetSemanticModel(tree);
var descendants = tree.GetCompilationUnitRoot().DescendantNodes();
var paras = descendants.OfType<ParameterSyntax>();
Assert.Equal(1, paras.Count());
var parasym = model.GetDeclaredSymbol(paras.First());
var ploc = parasym.Locations[0];
var args = descendants.OfType<ArgumentSyntax>().Where(s => s.ToString() == "index").Select(s => s);
Assert.Equal(2, args.Count());
var argsym1 = model.GetSymbolInfo(args.First().Expression).Symbol;
var argsym2 = model.GetSymbolInfo(args.Last().Expression).Symbol;
Assert.NotNull(argsym1);
Assert.NotNull(argsym2);
Assert.Equal(ploc, argsym1.Locations[0]);
Assert.Equal(ploc, argsym2.Locations[0]);
Assert.Equal(parasym.Kind, argsym1.Kind);
Assert.Equal(parasym.Kind, argsym2.Kind);
// SourceSimpleParameterSymbol vs. SourceClonedComplexParameterSymbol
Assert.NotEqual(parasym, argsym1);
Assert.NotEqual(parasym, argsym2);
}
[WorkItem(545648, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545648")]
[Fact]
public void AliasDeclaredSymbolWithConflict()
{
var source = @"
using X = System;
class X { }
";
var comp = (Compilation)CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var aliasSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingDirectiveSyntax>().Single();
var symbol = model.GetDeclaredSymbol(aliasSyntax);
Assert.Equal(symbol.Target, comp.GlobalNamespace.GetMember<INamespaceSymbol>("System"));
comp.VerifyDiagnostics(
// (2,1): info CS8019: Unnecessary using directive.
// using X = System;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using X = System;"));
}
[WorkItem(529751, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529751")]
[Fact]
public void ExternAlias()
{
var source = @"
extern alias X;
class Test
{
static void Main()
{
X::C c = null;
}
}
";
var comp1 = CreateCompilation("public class C { }");
var ref1 = comp1.EmitToImageReference(aliases: ImmutableArray.Create("X"));
var comp2 = CreateCompilation(source, new[] { ref1 });
var tree = comp2.SyntaxTrees.Single();
var model = comp2.GetSemanticModel(tree);
var aliasSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ExternAliasDirectiveSyntax>().Single();
// Compilation.GetExternAliasTarget defines this behavior: the target is a merged namespace
// with the same name as the alias, contained in the global namespace of the compilation.
var aliasSymbol = model.GetDeclaredSymbol(aliasSyntax);
var aliasTarget = (INamespaceSymbol)aliasSymbol.Target;
Assert.Equal(NamespaceKind.Module, aliasTarget.NamespaceKind);
Assert.Equal("", aliasTarget.Name);
Assert.True(aliasTarget.IsGlobalNamespace);
Assert.Null(aliasTarget.ContainingNamespace);
Assert.Equal(0, comp2.GlobalNamespace.GetMembers("X").Length); //Doesn't contain the alias target namespace as a child.
var aliasQualifiedSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AliasQualifiedNameSyntax>().Single();
Assert.Equal(aliasSymbol, model.GetAliasInfo(aliasQualifiedSyntax.Alias));
comp2.VerifyDiagnostics(
// (8,14): warning CS0219: The variable 'c' is assigned but its value is never used
// X::C c = null;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "c").WithArguments("c"));
}
[Fact, WorkItem(546687, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546687"), WorkItem(529751, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529751")]
public void ExternAliasWithoutTarget()
{
var source = @"
extern alias X;
class Test
{
static void Main()
{
X::C c = null;
}
}
";
var comp = CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var aliasSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ExternAliasDirectiveSyntax>().Single();
var aliasSymbol = model.GetDeclaredSymbol(aliasSyntax);
Assert.IsType<MissingNamespaceSymbol>(aliasSymbol.Target.GetSymbol());
var aliasQualifiedSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AliasQualifiedNameSyntax>().Single();
Assert.Equal(aliasSymbol, model.GetAliasInfo(aliasQualifiedSyntax.Alias));
comp.VerifyDiagnostics(
// (2,14): error CS0430: The extern alias 'X' was not specified in a /reference option
// extern alias X;
Diagnostic(ErrorCode.ERR_BadExternAlias, "X").WithArguments("X"),
// (8,12): error CS0234: The type or namespace name 'C' does not exist in the namespace 'X' (are you missing an assembly reference?)
// X::C c = null;
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "C").WithArguments("C", "X"));
}
[WorkItem(545648, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545648")]
[Fact]
public void UsingDirectiveAliasSemanticInfo()
{
var source = "using X = System;";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (1,1): info CS8019: Unnecessary using directive.
// using X = System;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using X = System;"));
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var aliasSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<NameEqualsSyntax>().Single().Name;
Assert.Equal(SymbolInfo.None, model.GetSymbolInfo(aliasSyntax));
var usingSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingDirectiveSyntax>().Single();
Assert.Equal(SymbolKind.Alias, model.GetDeclaredSymbol(usingSyntax).Kind);
}
[WorkItem(545882, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545882")]
[Fact]
public void SpeculativelyBindConstructorInitializerInPlaceOfActual()
{
var source = @"class C
{
C(int x) { }
C() : this((int) 1) { }
}";
var comp = (Compilation)CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var oldSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ConstructorInitializerSyntax>().Single();
var newSyntax = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer);
var info = model.GetSpeculativeSymbolInfo(oldSyntax.SpanStart, newSyntax);
var symbol = info.Symbol;
Assert.NotNull(symbol);
Assert.Equal(comp.GlobalNamespace.GetMember<INamedTypeSymbol>("C"), symbol.ContainingType);
Assert.Equal(SymbolKind.Method, symbol.Kind);
var method = (IMethodSymbol)symbol;
Assert.Equal(MethodKind.Constructor, method.MethodKind);
Assert.Empty(method.Parameters);
}
[WorkItem(545882, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545882")]
[Fact]
public void SpeculativelyBindConstructorInitializerInNewLocation()
{
var source = @"class C
{
C() { }
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var oldSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ConstructorDeclarationSyntax>().Single();
var newSyntax = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer);
var info = model.GetSpeculativeSymbolInfo(oldSyntax.ParameterList.Span.End, newSyntax);
Assert.Equal(SymbolInfo.None, info);
}
[Fact]
public void TestGetSpeculativeSemanticModelInFieldInitializer()
{
var compilation = CreateCompilation(@"
class C
{
object y = 1;
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var fieldDecl = (FieldDeclarationSyntax)typeDecl.Members[0];
var varDecl = fieldDecl.Declaration.Variables.First();
var model = compilation.GetSemanticModel(tree);
Assert.False(model.IsSpeculativeSemanticModel);
Assert.Null(model.ParentModel);
Assert.Equal(0, model.OriginalPositionForSpeculation);
// Speculate on the equals value syntax (initializer)
// Conversion info available, ConvertedType: Object.
var equalsValue = SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression(@"(string)""Hello"""));
var expr = equalsValue.Value;
int position = varDecl.Initializer.SpanStart;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(position, equalsValue, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
Assert.True(speculativeModel.IsSpeculativeSemanticModel);
Assert.Equal(model, speculativeModel.ParentModel);
Assert.Equal(position, speculativeModel.OriginalPositionForSpeculation);
var typeInfo = speculativeModel.GetTypeInfo(expr);
Assert.NotNull(typeInfo.Type);
Assert.Equal("String", typeInfo.Type.Name);
Assert.Equal("Object", typeInfo.ConvertedType.Name);
var constantInfo = speculativeModel.GetConstantValue(expr);
Assert.True(constantInfo.HasValue, "must be a constant");
Assert.Equal("Hello", constantInfo.Value);
}
[Fact]
public void TestGetSpeculativeSemanticModelInEnumMember()
{
var compilation = CreateCompilation(@"
enum C
{
y = 1
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (EnumDeclarationSyntax)root.Members[0];
var enumMemberDecl = (EnumMemberDeclarationSyntax)typeDecl.Members[0];
var equalsValue = enumMemberDecl.EqualsValue;
var initializer = equalsValue.Value;
var model = compilation.GetSemanticModel(tree);
// Speculate on the equals value syntax (initializer)
// Conversion info available, ConvertedType: Int32.
var newEqualsValue = SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("(short)0"));
var expr = newEqualsValue.Value;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
Assert.False(speculativeModel.IgnoresAccessibility);
var typeInfo = speculativeModel.GetTypeInfo(expr);
Assert.NotNull(typeInfo.Type);
Assert.Equal("Int16", typeInfo.Type.Name);
Assert.Equal("Int32", typeInfo.ConvertedType.Name);
var constantInfo = speculativeModel.GetConstantValue(expr);
Assert.True(constantInfo.HasValue, "must be a constant");
Assert.Equal((short)0, constantInfo.Value);
model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel);
Assert.True(speculativeModel.IgnoresAccessibility);
}
[Fact]
[WorkItem(648305, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/648305")]
public void TestGetSpeculativeSemanticModelInDefaultValueArgument()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x = 1)
{
string y = ""Hello"";
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var equalsValue = methodDecl.ParameterList.Parameters[0].Default;
var paramDefaultArg = equalsValue.Value;
var model = compilation.GetSemanticModel(tree);
var ti = model.GetTypeInfo(paramDefaultArg);
// Speculate on the equals value syntax (initializer)
// Conversion info available, ConvertedType: Int32.
var newEqualsValue = SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("(short)0"));
var expr = newEqualsValue.Value;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var typeInfo = speculativeModel.GetTypeInfo(expr);
Assert.NotNull(typeInfo.Type);
Assert.Equal("Int16", typeInfo.Type.Name);
Assert.Equal("Int32", typeInfo.ConvertedType.Name);
var constantInfo = speculativeModel.GetConstantValue(expr);
Assert.True(constantInfo.HasValue, "must be a constant");
Assert.Equal((short)0, constantInfo.Value);
}
[Fact]
[WorkItem(746002, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/746002")]
public void TestGetSpeculativeSemanticModelInDefaultValueArgument2()
{
var compilation = CreateCompilation(@"
using System;
enum E
{
A = 1,
B = 2
}
interface I
{
void M1(E e = E.A);
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var interfaceDecl = (TypeDeclarationSyntax)root.Members[1];
var methodDecl = (MethodDeclarationSyntax)interfaceDecl.Members[0];
var param = methodDecl.ParameterList.Parameters[0];
var equalsValue = param.Default;
var paramDefaultArg = equalsValue.Value;
var model = compilation.GetSemanticModel(tree);
// Speculate on the equals value syntax (initializer) with a non-null parent
var newEqualsValue = SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("E.B | E.A"));
newEqualsValue = param.ReplaceNode(equalsValue, newEqualsValue).Default;
var binaryExpr = newEqualsValue.Value;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var typeInfo = speculativeModel.GetTypeInfo(binaryExpr);
Assert.NotNull(typeInfo.Type);
Assert.Equal("E", typeInfo.Type.Name);
Assert.Equal("E", typeInfo.ConvertedType.Name);
}
[Fact]
[WorkItem(657701, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/657701")]
public void TestGetSpeculativeSemanticModelInConstructorDefaultValueArgument()
{
var compilation = CreateCompilation(@"
class C
{
C(int x = 1)
{
string y = ""Hello"";
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var constructorDecl = (ConstructorDeclarationSyntax)typeDecl.Members[0];
var equalsValue = constructorDecl.ParameterList.Parameters[0].Default;
var paramDefaultArg = equalsValue.Value;
var model = compilation.GetSemanticModel(tree);
var ti = model.GetTypeInfo(paramDefaultArg);
// Speculate on the equals value syntax (initializer)
// Conversion info available, ConvertedType: Int32.
var newEqualsValue = SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("(short)0"));
var expr = newEqualsValue.Value;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(equalsValue.SpanStart, newEqualsValue, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var typeInfo = speculativeModel.GetTypeInfo(expr);
Assert.NotNull(typeInfo.Type);
Assert.Equal("Int16", typeInfo.Type.Name);
Assert.Equal("Int32", typeInfo.ConvertedType.Name);
var constantInfo = speculativeModel.GetConstantValue(expr);
Assert.True(constantInfo.HasValue, "must be a constant");
Assert.Equal((short)0, constantInfo.Value);
}
[Fact]
public void TestGetSpeculativeSemanticModelInExpressionBody_Property()
{
var compilation = CreateCompilation(@"
class C
{
public object X => 0;
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var propertyDecl = (PropertyDeclarationSyntax)typeDecl.Members[0];
var expressionBody = propertyDecl.ExpressionBody;
TestExpressionBodySpeculation(compilation, tree, expressionBody);
}
[Fact]
public void TestGetSpeculativeSemanticModelInExpressionBody_Method()
{
var compilation = CreateCompilation(@"
class C
{
public object X() => 0;
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var expressionBody = methodDecl.ExpressionBody;
TestExpressionBodySpeculation(compilation, tree, expressionBody);
}
[Fact]
public void TestGetSpeculativeSemanticModelInExpressionBody_Indexer()
{
var compilation = CreateCompilation(@"
class C
{
public object this[int x] => 0;
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var indexerDecl = (IndexerDeclarationSyntax)typeDecl.Members[0];
var expressionBody = indexerDecl.ExpressionBody;
TestExpressionBodySpeculation(compilation, tree, expressionBody);
}
private static void TestExpressionBodySpeculation(Compilation compilation, SyntaxTree tree, ArrowExpressionClauseSyntax expressionBody)
{
var model = compilation.GetSemanticModel(tree);
Assert.False(model.IsSpeculativeSemanticModel);
Assert.Null(model.ParentModel);
Assert.Equal(0, model.OriginalPositionForSpeculation);
// Speculate on the expression body syntax.
// Conversion info available, ConvertedType: Object.
var newExpressionBody = SyntaxFactory.ArrowExpressionClause(SyntaxFactory.ParseExpression(@"(string)""Hello"""));
var expr = newExpressionBody.Expression;
int position = expressionBody.SpanStart;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(position, newExpressionBody, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
Assert.True(speculativeModel.IsSpeculativeSemanticModel);
Assert.Equal(model, speculativeModel.ParentModel);
Assert.Equal(position, speculativeModel.OriginalPositionForSpeculation);
var typeInfo = speculativeModel.GetTypeInfo(expr);
Assert.NotNull(typeInfo.Type);
Assert.Equal("String", typeInfo.Type.Name);
Assert.Equal("Object", typeInfo.ConvertedType.Name);
var constantInfo = speculativeModel.GetConstantValue(expr);
Assert.True(constantInfo.HasValue, "must be a constant");
Assert.Equal("Hello", constantInfo.Value);
}
[WorkItem(529893, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529893")]
[Fact]
public void AliasCalledVar()
{
var source = @"
using @var = Q;
class Q
{
var q;
}
";
var comp = (Compilation)CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,9): warning CS0169: The field 'Q.q' is never used
// var q;
Diagnostic(ErrorCode.WRN_UnreferencedField, "q").WithArguments("Q.q"));
var classQ = comp.GlobalNamespace.GetMember<INamedTypeSymbol>("Q");
var fieldQ = classQ.GetMember<IFieldSymbol>("q");
Assert.Equal(classQ, fieldQ.Type);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var aliasDecl = tree.GetRoot().DescendantNodes().OfType<UsingDirectiveSyntax>().Single();
var aliasSymbol = model.GetDeclaredSymbol(aliasDecl);
Assert.Equal(SymbolKind.Alias, aliasSymbol.Kind);
Assert.Equal(classQ, aliasSymbol.Target);
Assert.Equal("var", aliasSymbol.Name);
var aliasDeclInfo = model.GetSymbolInfo(aliasDecl.Alias.Name);
Assert.Null(aliasDeclInfo.Symbol);
Assert.Equal(CandidateReason.None, aliasDeclInfo.CandidateReason);
var fieldDecl = tree.GetRoot().DescendantNodes().OfType<FieldDeclarationSyntax>().Single();
var fieldSymbol = model.GetDeclaredSymbol(fieldDecl.Declaration.Variables.Single());
Assert.Equal(fieldQ, fieldSymbol);
var typeSyntax = (IdentifierNameSyntax)fieldDecl.Declaration.Type;
var fieldTypeInfo = model.GetSymbolInfo(typeSyntax);
Assert.Equal(classQ, fieldTypeInfo.Symbol);
var fieldTypeAliasInfo = model.GetAliasInfo(typeSyntax);
Assert.Equal(aliasSymbol, fieldTypeAliasInfo);
}
[Fact]
public void TestGetSpeculativeSemanticModelForStatement()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 1000;
}
}
");
var statement = (BlockSyntax)SyntaxFactory.ParseStatement(@"
{
int z = 0;
M(z);
M(y);
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].SpanStart, statement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var localDecl = (LocalDeclarationStatementSyntax)statement.Statements[0];
var declarator = localDecl.Declaration.Variables.First();
var local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("z", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("Int32", ((ILocalSymbol)local).Type.Name);
var typeInfo = speculativeModel.GetTypeInfo(localDecl.Declaration.Type);
Assert.NotNull(typeInfo.Type);
Assert.Equal("Int32", typeInfo.Type.Name);
var call = (InvocationExpressionSyntax)((ExpressionStatementSyntax)statement.Statements[1]).Expression;
var arg = call.ArgumentList.Arguments[0].Expression;
var info = speculativeModel.GetSymbolInfo(arg);
Assert.NotNull(info.Symbol);
Assert.Equal("z", info.Symbol.Name);
Assert.Equal(SymbolKind.Local, info.Symbol.Kind);
var call2 = (InvocationExpressionSyntax)((ExpressionStatementSyntax)((BlockSyntax)statement).Statements[2]).Expression;
var arg2 = call2.ArgumentList.Arguments[0].Expression;
var info2 = speculativeModel.GetSymbolInfo(arg2);
Assert.NotNull(info2.Symbol);
Assert.Equal("y", info2.Symbol.Name);
Assert.Equal(SymbolKind.Local, info2.Symbol.Kind);
}
[Fact]
public void TestGetSpeculativeSemanticModelForStatement_DeclaredLocal()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 1000;
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
// different name local
var statement = SyntaxFactory.ParseStatement(@"int z = 0;");
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].SpanStart, statement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var declarator = ((LocalDeclarationStatementSyntax)statement).Declaration.Variables.First();
var local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("z", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("Int32", ((ILocalSymbol)local).Type.Name);
// same name local
statement = SyntaxFactory.ParseStatement(@"string y = null;");
success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].SpanStart, statement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
declarator = ((LocalDeclarationStatementSyntax)statement).Declaration.Variables.First();
local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("y", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("String", ((ILocalSymbol)local).Type.Name);
}
[Fact]
public void TestGetSpeculativeSemanticModelForStatement_GetDeclaredLabelSymbol()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 1000;
}
}
");
var labeledStatement = SyntaxFactory.ParseStatement(@"label: y++;");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
SemanticModel statModel;
bool success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].SpanStart, labeledStatement, out statModel);
Assert.True(success);
Assert.NotNull(statModel);
var label = statModel.GetDeclaredSymbol(labeledStatement);
Assert.NotNull(label);
Assert.Equal("label", label.Name);
Assert.Equal(SymbolKind.Label, label.Kind);
}
[Fact]
public void TestGetSpeculativeSemanticModelForStatement_GetDeclaredSwitchLabelSymbol()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 0;
}
}
");
var switchStatement = (SwitchStatementSyntax)SyntaxFactory.ParseStatement(@"
switch (y)
{
case 0:
y++;
break;
}");
var switchLabel = switchStatement.Sections[0].Labels[0];
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
SemanticModel statModel;
bool success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].Span.End, switchStatement, out statModel);
Assert.True(success);
Assert.NotNull(statModel);
var symbol = ((CSharp.Symbols.PublicModel.LabelSymbol)statModel.GetDeclaredSymbol(switchLabel))?.UnderlyingSymbol;
Assert.NotNull(symbol);
Assert.IsType<SourceLabelSymbol>(symbol);
var labelSymbol = (SourceLabelSymbol)symbol;
Assert.Equal(ConstantValue.Default(SpecialType.System_Int32), labelSymbol.SwitchCaseLabelConstant);
Assert.Equal(switchLabel, labelSymbol.IdentifierNodeOrToken.AsNode());
Assert.Equal("case 0:", labelSymbol.Name);
}
[Fact]
public void TestGetSpeculativeSemanticModelForStatement_GetDeclaredLambdaParameterSymbol()
{
var compilation = CreateCompilationWithMscorlib40AndSystemCore(@"
using System.Linq;
class C
{
void M(int x)
{
int y = 0;
}
}
");
var speculatedStatement = (LocalDeclarationStatementSyntax)SyntaxFactory.ParseStatement(@"Func<int, int> var = (z) => x + z;");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].Span.End, speculatedStatement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var lambdaExpression = speculatedStatement.DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().FirstOrDefault();
var lambdaParam = lambdaExpression.ParameterList.Parameters[0];
var parameterSymbol = speculativeModel.GetDeclaredSymbol(lambdaParam);
Assert.NotNull(parameterSymbol);
Assert.Equal("z", parameterSymbol.Name);
}
[Fact]
public void TestGetSpeculativeSemanticModelForStatement_ForEach()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
var a = new [] {1, 2, 3};
}
}
");
var statement = (ForEachStatementSyntax)SyntaxFactory.ParseStatement(@"
foreach(short ele in a)
{
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].SpanStart, statement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
ForEachStatementInfo info = speculativeModel.GetForEachStatementInfo(statement);
Assert.NotEqual(default, info);
Assert.Equal("System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()", info.GetEnumeratorMethod.ToTestDisplayString());
Assert.Equal("System.Object System.Collections.IEnumerator.Current.get", info.CurrentProperty.GetMethod.ToTestDisplayString());
Assert.Equal("System.Boolean System.Collections.IEnumerator.MoveNext()", info.MoveNextMethod.ToTestDisplayString());
Assert.Equal("void System.IDisposable.Dispose()", info.DisposeMethod.ToTestDisplayString());
}
[Fact]
public void TestGetSpeculativeSemanticModelInAutoPropInitializer1()
{
var source = @"class C
{
int y = 0;
int X { get; } = 1;
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
Assert.False(model.IsSpeculativeSemanticModel);
Assert.Null(model.ParentModel);
Assert.Equal(0, model.OriginalPositionForSpeculation);
// Speculate on the initializer
var root = tree.GetCompilationUnitRoot();
var oldSyntax = root.DescendantNodes()
.OfType<EqualsValueClauseSyntax>().ElementAt(1);
var position = oldSyntax.SpanStart;
var newSyntax = SyntaxFactory.EqualsValueClause(
SyntaxFactory.ParseExpression("this.y"));
var expr = newSyntax.Value;
SemanticModel speculativeModel;
bool success = model.TryGetSpeculativeSemanticModel(oldSyntax.SpanStart,
newSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
Assert.True(speculativeModel.IsSpeculativeSemanticModel);
Assert.Equal(model, speculativeModel.ParentModel);
Assert.Equal(position, speculativeModel.OriginalPositionForSpeculation);
var typeInfo = speculativeModel.GetTypeInfo(expr);
Assert.NotEqual(default, typeInfo);
Assert.Equal("Int32", typeInfo.Type.Name);
var thisSyntax = expr.DescendantNodes().OfType<ThisExpressionSyntax>().Single();
var symbolInfo = speculativeModel.GetSpeculativeSymbolInfo(
thisSyntax.SpanStart,
thisSyntax, SpeculativeBindingOption.BindAsExpression);
Assert.NotEqual(default, symbolInfo);
var candidates = symbolInfo.CandidateSymbols;
Assert.Equal(1, candidates.Length);
Assert.IsType<ThisParameterSymbol>(candidates[0].GetSymbol());
Assert.Equal(CandidateReason.NotReferencable, symbolInfo.CandidateReason);
}
[Fact]
public void TestGetSpeculativeSemanticModelForConstructorInitializer()
{
var source = @"class C
{
C(int x) { }
C() : this((int) 1) { }
}";
var comp = (Compilation)CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var parentModel = comp.GetSemanticModel(tree);
var oldSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ConstructorInitializerSyntax>().Single();
var newSyntax = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer);
SemanticModel speculativeModel;
bool success = parentModel.TryGetSpeculativeSemanticModel(oldSyntax.SpanStart, newSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var info = speculativeModel.GetSymbolInfo(newSyntax);
var symbol = info.Symbol;
Assert.NotNull(symbol);
Assert.Equal(comp.GlobalNamespace.GetMember<INamedTypeSymbol>("C"), symbol.ContainingType);
Assert.Equal(SymbolKind.Method, symbol.Kind);
var method = (IMethodSymbol)symbol;
Assert.Equal(MethodKind.Constructor, method.MethodKind);
Assert.Empty(method.Parameters);
// test unnecessary cast removal
var newArgument = SyntaxFactory.ParseExpression("1");
newSyntax = oldSyntax.ReplaceNode(oldSyntax.DescendantNodes().OfType<CastExpressionSyntax>().Single(), newArgument);
success = parentModel.TryGetSpeculativeSemanticModel(oldSyntax.SpanStart, newSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
info = speculativeModel.GetSymbolInfo(newSyntax);
symbol = info.Symbol;
Assert.NotNull(symbol);
Assert.Equal(comp.GlobalNamespace.GetMember<INamedTypeSymbol>("C"), symbol.ContainingType);
Assert.Equal(SymbolKind.Method, symbol.Kind);
method = (IMethodSymbol)symbol;
Assert.Equal(MethodKind.Constructor, method.MethodKind);
Assert.Equal(1, method.Parameters.Length);
// test incorrect cast replacement
newArgument = SyntaxFactory.ParseExpression("(string) 1");
newSyntax = oldSyntax.ReplaceNode(oldSyntax.DescendantNodes().OfType<CastExpressionSyntax>().Single(), newArgument);
success = parentModel.TryGetSpeculativeSemanticModel(oldSyntax.SpanStart, newSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
info = speculativeModel.GetSymbolInfo(newSyntax);
symbol = info.Symbol;
Assert.Null(symbol);
Assert.Equal(CandidateReason.OverloadResolutionFailure, info.CandidateReason);
Assert.Equal(2, info.CandidateSymbols.Length);
var sortedCandidates = info.CandidateSymbols.OrderBy(s => s.ToTestDisplayString()).ToArray();
Assert.Equal("C..ctor()", sortedCandidates[0].ToTestDisplayString());
Assert.Equal(SymbolKind.Method, sortedCandidates[0].Kind);
Assert.Equal("C..ctor(System.Int32 x)", sortedCandidates[1].ToTestDisplayString());
Assert.Equal(SymbolKind.Method, sortedCandidates[1].Kind);
}
[WorkItem(545882, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545882")]
[Fact]
public void TestGetSpeculativeSemanticModelForConstructorInitializer_UnsupportedLocation()
{
var source = @"class C
{
C() { }
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var parentModel = comp.GetSemanticModel(tree);
var oldSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ConstructorDeclarationSyntax>().Single();
var newSyntax = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer);
SemanticModel speculativeModel;
bool success = parentModel.TryGetSpeculativeSemanticModel(oldSyntax.SpanStart, newSyntax, out speculativeModel);
Assert.False(success);
Assert.Null(speculativeModel);
}
[Fact]
public void TestArgumentsToGetSpeculativeSemanticModelAPI()
{
var compilation = CreateCompilation(@"
class C
{
public C(): this(0) {}
public C(int i) {}
[System.Obsolete]
void M(int x)
{
string y = ""Hello"";
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var ctor1 = (ConstructorDeclarationSyntax)typeDecl.Members[0];
var ctor2 = (ConstructorDeclarationSyntax)typeDecl.Members[1];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[2];
var model = compilation.GetSemanticModel(tree);
var statement = (LocalDeclarationStatementSyntax)methodDecl.Body.Statements[0];
var initializer = statement.Declaration.Variables[0].Initializer;
var ctorInitializer = ctor1.Initializer;
var attribute = methodDecl.AttributeLists[0].Attributes[0];
SemanticModel speculativeModel;
Assert.Throws<ArgumentNullException>(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, statement: null, speculativeModel: out speculativeModel));
Assert.Throws<ArgumentNullException>(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, constructorInitializer: (ConstructorInitializerSyntax)null, speculativeModel: out speculativeModel));
Assert.Throws<ArgumentNullException>(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, attribute: null, speculativeModel: out speculativeModel));
// Speculate on a node from the same syntax tree.
Assert.Throws<ArgumentException>(() => model.TryGetSpeculativeSemanticModel(statement.SpanStart, statement: statement, speculativeModel: out speculativeModel));
Assert.Throws<ArgumentException>(() => model.TryGetSpeculativeSemanticModel(ctorInitializer.SpanStart, constructorInitializer: ctorInitializer, speculativeModel: out speculativeModel));
Assert.Throws<ArgumentException>(() => model.TryGetSpeculativeSemanticModel(attribute.SpanStart, attribute: attribute, speculativeModel: out speculativeModel));
// Chaining speculative semantic model is not supported.
var speculatedStatement = statement.ReplaceNode(initializer.Value, SyntaxFactory.ParseExpression("0"));
model.TryGetSpeculativeSemanticModel(statement.SpanStart, speculatedStatement, speculativeModel: out speculativeModel);
Assert.Throws<InvalidOperationException>(() => speculativeModel.TryGetSpeculativeSemanticModel(speculatedStatement.SpanStart, speculatedStatement, speculativeModel: out speculativeModel));
}
[Fact]
public void TestGetSpeculativeSemanticModelOnSpeculativeSemanticModel()
{
var compilation = CreateCompilation(@"
class C
{
public C(): this(0) {}
public C(int i) {}
[System.Obsolete]
void M(int x)
{
string y = ""Hello"";
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var ctor1 = (ConstructorDeclarationSyntax)typeDecl.Members[0];
var ctor2 = (ConstructorDeclarationSyntax)typeDecl.Members[1];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[2];
var model = compilation.GetSemanticModel(tree);
var statement = (LocalDeclarationStatementSyntax)methodDecl.Body.Statements[0];
var expression = statement.Declaration.Variables[0].Initializer.Value;
var ctorInitializer = ctor1.Initializer;
var attribute = methodDecl.AttributeLists[0].Attributes[0];
var speculatedStatement = statement.ReplaceNode(expression, SyntaxFactory.ParseExpression("0"));
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(statement.SpanStart, speculatedStatement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
// Chaining speculative semantic model is not supported.
// (a) Expression
var newSpeculatedStatement = statement.ReplaceNode(expression, SyntaxFactory.ParseExpression("1.1"));
SemanticModel newModel;
Assert.Throws<InvalidOperationException>(() => speculativeModel.TryGetSpeculativeSemanticModel(speculatedStatement.SpanStart, newSpeculatedStatement, out newModel));
// (b) Statement
newSpeculatedStatement = (LocalDeclarationStatementSyntax)SyntaxFactory.ParseStatement(@"int z = 0;");
Assert.Throws<InvalidOperationException>(() => speculativeModel.TryGetSpeculativeSemanticModel(speculatedStatement.SpanStart, newSpeculatedStatement, out newModel));
}
[Fact]
public void TestGetSpeculativeSemanticModelInsideUnsafeCode()
{
var compilation = CreateCompilation(@"
unsafe class C
{
void M()
{
int x;
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
var unsafeStatement = (LocalDeclarationStatementSyntax)SyntaxFactory.ParseStatement("int *p = &x;");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.Statements[0].Span.End, unsafeStatement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var declarator = unsafeStatement.Declaration.Variables.First();
var initializer = declarator.Initializer.Value;
var binder = ((CSharpSemanticModel)speculativeModel).GetEnclosingBinder(initializer.SpanStart);
Assert.True(binder.InUnsafeRegion, "must be in unsafe code");
Assert.True(binder.IsSemanticModelBinder, "must be speculative");
var typeInfo = speculativeModel.GetTypeInfo(initializer);
Assert.Equal("System.Int32*", typeInfo.Type.ToTestDisplayString());
Assert.Equal(TypeKind.Pointer, typeInfo.Type.TypeKind);
Assert.Equal("System.Int32*", typeInfo.ConvertedType.ToTestDisplayString());
Assert.Equal(TypeKind.Pointer, typeInfo.ConvertedType.TypeKind);
var conv = speculativeModel.GetConversion(initializer);
Assert.Equal(ConversionKind.Identity, conv.Kind);
var symbol = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.Local, symbol.Kind);
Assert.Equal("p", symbol.Name);
}
[WorkItem(663704, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/663704")]
[Fact]
public void TestGetSpeculativeSemanticModelInsideUnknownAccessor()
{
var source = @"
class C
{
C P
{
goo
{
return null;
}
}
}
";
var comp = CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var accessorSyntax = tree.GetRoot().DescendantNodes().OfType<AccessorDeclarationSyntax>().Single();
Assert.Equal(SyntaxKind.UnknownAccessorDeclaration, accessorSyntax.Kind());
var statementSyntax = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single();
var memberModel = ((CSharpSemanticModel)model).GetMemberModel(statementSyntax);
Assert.Null(memberModel); // No member model since no symbol.
var speculativeSyntax = SyntaxFactory.ParseStatement("return default(C);");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(statementSyntax.SpanStart, speculativeSyntax, out speculativeModel);
Assert.False(success);
Assert.Null(speculativeModel);
}
[Fact]
public void TestGetSpeculativeSemanticModelForMethodBody()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 1000;
}
}
");
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"
{
int z = 0;
M(z);
M(y); // Should generate error here as we are replacing the method body.
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
VerifySpeculativeSemanticModelForMethodBody(blockStatement, speculativeModel);
}
[Fact()]
[WorkItem(10211, "https://github.com/dotnet/roslyn/issues/10211")]
public void GetDependenceChainRegression_10211_working()
{
var compilation = CreateEmptyCompilation(@"
class Parent {}
class Child : Parent {}
");
var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees[0]);
// Ensure that we don't crash here.
semanticModel.GetMethodBodyDiagnostics();
}
[Fact()]
[WorkItem(10211, "https://github.com/dotnet/roslyn/issues/10211")]
public void GetDependenceChainRegression_10211()
{
var compilation = CreateEmptyCompilation(@"
class Child : Parent {}
class Parent {}
");
var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees[0]);
// Ensure that we don't crash here.
semanticModel.GetMethodBodyDiagnostics();
}
private static void VerifySpeculativeSemanticModelForMethodBody(BlockSyntax blockStatement, SemanticModel speculativeModel)
{
var localDecl = (LocalDeclarationStatementSyntax)blockStatement.Statements[0];
var declarator = localDecl.Declaration.Variables.First();
var local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("z", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("Int32", ((ILocalSymbol)local).Type.Name);
var typeInfo = speculativeModel.GetTypeInfo(localDecl.Declaration.Type);
Assert.NotNull(typeInfo.Type);
Assert.Equal("Int32", typeInfo.Type.Name);
var call = (InvocationExpressionSyntax)((ExpressionStatementSyntax)blockStatement.Statements[1]).Expression;
var arg = call.ArgumentList.Arguments[0].Expression;
var info = speculativeModel.GetSymbolInfo(arg);
Assert.NotNull(info.Symbol);
Assert.Equal("z", info.Symbol.Name);
Assert.Equal(SymbolKind.Local, info.Symbol.Kind);
// Shouldn't bind to local y in the original method as we are replacing the method body.
var call2 = (InvocationExpressionSyntax)((ExpressionStatementSyntax)((BlockSyntax)blockStatement).Statements[2]).Expression;
var arg2 = call2.ArgumentList.Arguments[0].Expression;
var info2 = speculativeModel.GetSymbolInfo(arg2);
Assert.Null(info2.Symbol);
}
[Fact]
public void TestGetSpeculativeSemanticModelForIndexerAccessorBody()
{
var compilation = CreateCompilation(@"
class C
{
private int this[int x]
{
set
{
int y = 1000;
}
}
}
");
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"
{
int z = 0;
M(z);
M(y); // Should generate error here as we are replacing the method body.
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var indexerDecl = (IndexerDeclarationSyntax)typeDecl.Members[0];
var methodDecl = indexerDecl.AccessorList.Accessors[0];
var model = compilation.GetSemanticModel(tree);
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
VerifySpeculativeSemanticModelForMethodBody(blockStatement, speculativeModel);
}
[Fact]
public void TestGetSpeculativeSemanticModelForPropertyAccessorBody()
{
var compilation = CreateCompilation(@"
class C
{
private int M
{
set
{
int y = 1000;
}
}
}
");
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"
{
int z = 0;
M(z);
M(y); // Should generate error here as we are replacing the method body.
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var propertyDecl = (PropertyDeclarationSyntax)typeDecl.Members[0];
var methodDecl = propertyDecl.AccessorList.Accessors[0];
var model = compilation.GetSemanticModel(tree);
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
VerifySpeculativeSemanticModelForMethodBody(blockStatement, speculativeModel);
}
[Fact]
public void TestGetSpeculativeSemanticModelForEventAccessorBody()
{
var compilation = CreateCompilation(@"
class C
{
private event System.Action E
{
add
{
int y = 1000;
}
remove
{
}
}
}
");
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"
{
int z = 0;
M(z);
M(y); // Should generate error here as we are replacing the method body.
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var eventDecl = (EventDeclarationSyntax)typeDecl.Members[0];
var methodDecl = eventDecl.AccessorList.Accessors[0];
var model = compilation.GetSemanticModel(tree);
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
VerifySpeculativeSemanticModelForMethodBody(blockStatement, speculativeModel);
}
[Fact]
public void TestGetSpeculativeSemanticModelForMethodBody_DeclaredLocal()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 1000;
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
// different name local
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"{ int z = 0; }");
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var declarator = ((LocalDeclarationStatementSyntax)blockStatement.Statements[0]).Declaration.Variables.First();
var local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("z", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("Int32", ((ILocalSymbol)local).Type.Name);
// same name local
blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"{ string y = null; }");
speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
declarator = ((LocalDeclarationStatementSyntax)blockStatement.Statements[0]).Declaration.Variables.First();
local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("y", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("String", ((ILocalSymbol)local).Type.Name);
// parameter symbol
blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"{ var y = x; }");
speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
declarator = ((LocalDeclarationStatementSyntax)blockStatement.Statements[0]).Declaration.Variables.First();
local = speculativeModel.GetDeclaredSymbol(declarator);
Assert.NotNull(local);
Assert.Equal("y", local.Name);
Assert.Equal(SymbolKind.Local, local.Kind);
Assert.Equal("Int32", ((ILocalSymbol)local).Type.Name);
var param = speculativeModel.GetSymbolInfo(declarator.Initializer.Value).Symbol;
Assert.NotNull(param);
Assert.Equal(SymbolKind.Parameter, param.Kind);
var paramSymbol = (IParameterSymbol)param;
Assert.Equal("x", paramSymbol.Name);
Assert.Equal("Int32", paramSymbol.Type.Name);
}
[Fact]
public void TestGetSpeculativeSemanticModelForMethodBody_GetDeclaredLabelSymbol()
{
var compilation = CreateCompilation(@"
class C
{
void M(int x)
{
int y = 1000;
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"{ label: y++; }");
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
var labeledStatement = blockStatement.Statements[0];
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var label = speculativeModel.GetDeclaredSymbol(labeledStatement);
Assert.NotNull(label);
Assert.Equal("label", label.Name);
Assert.Equal(SymbolKind.Label, label.Kind);
}
[Fact]
public void TestGetSpeculativeSemanticModelForMethodBody_GetDeclaredLambdaParameterSymbol()
{
var compilation = CreateCompilationWithMscorlib40AndSystemCore(@"
using System.Linq;
class C
{
void M(int x)
{
int z = 0;
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"{ Func<int, int> var = (z) => x + z; }");
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].Span.End, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var lambdaExpression = blockStatement.Statements[0].DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().FirstOrDefault();
var lambdaParam = lambdaExpression.ParameterList.Parameters[0];
var parameterSymbol = speculativeModel.GetDeclaredSymbol(lambdaParam);
Assert.NotNull(parameterSymbol);
Assert.Equal("z", parameterSymbol.Name);
}
private static void TestGetSpeculativeSemanticModelForTypeSyntax_Common(
SemanticModel model,
int position,
TypeSyntax speculatedTypeSyntax,
SpeculativeBindingOption bindingOption,
SymbolKind expectedSymbolKind,
string expectedTypeDisplayString)
{
Assert.False(model.IsSpeculativeSemanticModel);
Assert.Null(model.ParentModel);
Assert.Equal(0, model.OriginalPositionForSpeculation);
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, speculatedTypeSyntax, out speculativeModel, bindingOption);
Assert.True(success);
Assert.NotNull(speculativeModel);
Assert.False(speculativeModel.IgnoresAccessibility);
Assert.True(speculativeModel.IsSpeculativeSemanticModel);
Assert.Equal(model, speculativeModel.ParentModel);
Assert.NotNull(speculativeModel);
Assert.Equal(position, speculativeModel.OriginalPositionForSpeculation);
var symbol = speculativeModel.GetSymbolInfo(speculatedTypeSyntax).Symbol;
Assert.NotNull(symbol);
Assert.Equal(expectedSymbolKind, symbol.Kind);
Assert.Equal(expectedTypeDisplayString, symbol.ToDisplayString());
var typeSymbol = speculativeModel.GetTypeInfo(speculatedTypeSyntax).Type;
Assert.NotNull(symbol);
Assert.Equal(expectedSymbolKind, symbol.Kind);
Assert.Equal(expectedTypeDisplayString, symbol.ToDisplayString());
if (speculatedTypeSyntax.Kind() == SyntaxKind.QualifiedName)
{
var right = ((QualifiedNameSyntax)speculatedTypeSyntax).Right;
symbol = speculativeModel.GetSymbolInfo(right).Symbol;
Assert.NotNull(symbol);
Assert.Equal(expectedSymbolKind, symbol.Kind);
Assert.Equal(expectedTypeDisplayString, symbol.ToDisplayString());
typeSymbol = speculativeModel.GetTypeInfo(right).Type;
Assert.NotNull(symbol);
Assert.Equal(expectedSymbolKind, symbol.Kind);
Assert.Equal(expectedTypeDisplayString, symbol.ToDisplayString());
}
}
[Fact]
public void TestGetSpeculativeSemanticModelForMethodBody_SwitchStatement()
{
var compilation = CreateCompilation(@"
using System;
class C
{
void M(int x)
{
switch(x)
{
case 0:
Console.WriteLine(x);
break;
}
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
var blockStatement = (BlockSyntax)SyntaxFactory.ParseStatement(@"{
switch(x)
{
case 1:
Console.WriteLine(x);
break;
}
}");
var speculatedMethod = methodDecl.ReplaceNode(methodDecl.Body, blockStatement);
blockStatement = speculatedMethod.Body;
var switchStatement = (SwitchStatementSyntax)blockStatement.Statements[0];
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModelForMethodBody(methodDecl.Body.Statements[0].SpanStart, speculatedMethod, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var switchLabel = switchStatement.Sections[0].Labels[0] as CaseSwitchLabelSyntax;
Assert.NotNull(switchLabel);
var constantVal = speculativeModel.GetConstantValue(switchLabel.Value);
Assert.True(constantVal.HasValue);
Assert.Equal(1, constantVal.Value);
}
[Fact]
public void TestGetSpeculativeSemanticModelForTypeSyntax_InGlobalUsing()
{
var compilation = CreateCompilation(@"using System.Runtime;");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var usingStatement = root.Usings[0];
var model = compilation.GetSemanticModel(tree);
var speculatedUsingExpression = SyntaxFactory.ParseName("System.Collections");
TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, usingStatement.Name.Position,
speculatedUsingExpression, SpeculativeBindingOption.BindAsTypeOrNamespace, SymbolKind.Namespace, "System.Collections");
}
[Fact]
public void TestGetSpeculativeSemanticModelForTypeSyntax_InGlobalAlias()
{
var compilation = CreateCompilation(@"using A = System.Exception;");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var usingStatement = root.Usings[0];
var model = compilation.GetSemanticModel(tree);
var speculatedUsingExpression = SyntaxFactory.ParseName("System.ArgumentException");
TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, usingStatement.Name.Position,
speculatedUsingExpression, SpeculativeBindingOption.BindAsExpression, SymbolKind.NamedType, "System.ArgumentException");
}
[Fact]
public void TestGetSpeculativeSemanticModelForTypeSyntax_InBaseList()
{
var compilation = CreateCompilation(@"
class MyException : System.Exception
{
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var baseList = typeDecl.BaseList;
var model = compilation.GetSemanticModel(tree);
var speculatedTypeExpression = SyntaxFactory.ParseName("System.ArgumentException");
TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, baseList.SpanStart,
speculatedTypeExpression, SpeculativeBindingOption.BindAsTypeOrNamespace, SymbolKind.NamedType, "System.ArgumentException");
model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
SemanticModel speculativeModel;
model.TryGetSpeculativeSemanticModel(baseList.SpanStart, speculatedTypeExpression, out speculativeModel);
Assert.True(speculativeModel.IgnoresAccessibility);
}
[Fact]
public void TestGetSpeculativeSemanticModelForTypeSyntax_InMemberDeclaration()
{
var compilation = CreateCompilation(@"
class Program
{
System.Exception field = null;
System.Exception Method(System.Exception param)
{
return field;
}
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var fieldDecl = (FieldDeclarationSyntax)typeDecl.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[1];
var model = compilation.GetSemanticModel(tree);
var speculatedTypeExpression = SyntaxFactory.ParseName("System.ArgumentException");
TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, fieldDecl.SpanStart,
speculatedTypeExpression, SpeculativeBindingOption.BindAsTypeOrNamespace, SymbolKind.NamedType, "System.ArgumentException");
TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, methodDecl.ReturnType.SpanStart,
speculatedTypeExpression, SpeculativeBindingOption.BindAsTypeOrNamespace, SymbolKind.NamedType, "System.ArgumentException");
TestGetSpeculativeSemanticModelForTypeSyntax_Common(model, methodDecl.ParameterList.Parameters.First().SpanStart,
speculatedTypeExpression, SpeculativeBindingOption.BindAsTypeOrNamespace, SymbolKind.NamedType, "System.ArgumentException");
}
[Fact]
public void TestGetSpeculativeSemanticModelForTypeSyntax_AliasName()
{
var compilation = CreateCompilation(@"
using A = System.ArgumentException;
class Program
{
System.Exception field = null;
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var fieldDecl = (FieldDeclarationSyntax)typeDecl.Members[0];
var model = compilation.GetSemanticModel(tree);
var speculatedAliasName = SyntaxFactory.ParseName("A");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(fieldDecl.SpanStart, speculatedAliasName, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var symbol = speculativeModel.GetAliasInfo(speculatedAliasName);
Assert.NotNull(symbol);
Assert.Equal("A", symbol.ToDisplayString());
Assert.Equal("System.ArgumentException", symbol.Target.ToDisplayString());
}
[Fact]
public void TestGetSpeculativeSemanticModelForTypeCrefSyntax()
{
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(@"
/// <summary>
/// <see cref=""int""/>
/// </summary>
class A { }
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var cref = typeDecl.DescendantNodes(descendIntoTrivia: true).OfType<TypeCrefSyntax>().Single();
var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree);
var symbol = model.GetSymbolInfo(cref.Type).Symbol;
Assert.NotNull(symbol);
Assert.Equal("int", symbol.ToDisplayString());
var speculatedCref = (TypeCrefSyntax)SyntaxFactory.ParseCref("object");
// TryGetSpeculativeSemanticModel
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(cref.SpanStart, speculatedCref, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
symbol = speculativeModel.GetSymbolInfo(speculatedCref.Type).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("object", symbol.ToDisplayString());
// GetSpeculativeSymbolInfo
symbol = model.GetSpeculativeSymbolInfo(cref.SpanStart, speculatedCref).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("object", symbol.ToDisplayString());
}
[Fact]
public void TestGetSpeculativeSemanticModelForNameMemberCrefSyntax()
{
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(@"
/// <summary>
/// <see cref=""int""/>
/// </summary>
class A { }
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var cref = typeDecl.DescendantNodes(descendIntoTrivia: true).OfType<TypeCrefSyntax>().Single();
var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree);
var symbol = model.GetSymbolInfo(cref.Type).Symbol;
Assert.NotNull(symbol);
Assert.Equal("int", symbol.ToDisplayString());
var speculatedCref = (NameMemberCrefSyntax)SyntaxFactory.ParseCref("A");
// TryGetSpeculativeSemanticModel
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(cref.SpanStart, speculatedCref, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
symbol = speculativeModel.GetSymbolInfo(speculatedCref.Name).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A", symbol.ToDisplayString());
// GetSpeculativeSymbolInfo
symbol = model.GetSpeculativeSymbolInfo(cref.SpanStart, speculatedCref).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A", symbol.ToDisplayString());
}
[Fact]
public void TestGetSpeculativeSemanticModelForQualifiedCrefSyntax()
{
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(@"
/// <summary>
/// <see cref=""int""/>
/// </summary>
class A
{
class B { }
static void M() { }
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var cref = typeDecl.DescendantNodes(descendIntoTrivia: true).OfType<TypeCrefSyntax>().Single();
var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree);
var symbol = model.GetSymbolInfo(cref.Type).Symbol;
Assert.NotNull(symbol);
Assert.Equal("int", symbol.ToDisplayString());
var speculatedCref = (QualifiedCrefSyntax)SyntaxFactory.ParseCref("A.B");
// Type member: TryGetSpeculativeSemanticModel
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(cref.SpanStart, speculatedCref, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
symbol = speculativeModel.GetSymbolInfo(speculatedCref).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A.B", symbol.ToDisplayString());
symbol = speculativeModel.GetSymbolInfo(speculatedCref.Member).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A.B", symbol.ToDisplayString());
symbol = speculativeModel.GetTypeInfo(speculatedCref.Container).Type;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A", symbol.ToDisplayString());
// Type member: GetSpeculativeSymbolInfo
symbol = model.GetSpeculativeSymbolInfo(cref.SpanStart, speculatedCref).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A.B", symbol.ToDisplayString());
// Method member: TryGetSpeculativeSemanticModel
speculatedCref = (QualifiedCrefSyntax)SyntaxFactory.ParseCref("A.M");
success = model.TryGetSpeculativeSemanticModel(cref.SpanStart, speculatedCref, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
symbol = speculativeModel.GetSymbolInfo(speculatedCref).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.Method, symbol.Kind);
Assert.Equal("A.M()", symbol.ToDisplayString());
symbol = speculativeModel.GetSymbolInfo(speculatedCref.Member).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.Method, symbol.Kind);
Assert.Equal("A.M()", symbol.ToDisplayString());
symbol = speculativeModel.GetTypeInfo(speculatedCref.Container).Type;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.NamedType, symbol.Kind);
Assert.Equal("A", symbol.ToDisplayString());
// Method member: GetSpeculativeSymbolInfo
symbol = model.GetSpeculativeSymbolInfo(cref.SpanStart, speculatedCref).Symbol;
Assert.NotNull(symbol);
Assert.Equal(SymbolKind.Method, symbol.Kind);
Assert.Equal("A.M()", symbol.ToDisplayString());
}
[Fact]
public void TestGetSpeculativeSemanticModelForCrefSyntax_InvalidPosition()
{
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(@"
/// <summary>
/// <see cref=""int""/>
/// </summary>
class A
{
static void M() { }
}
");
var tree = compilation.SyntaxTrees[0];
var root = tree.GetCompilationUnitRoot();
var typeDecl = (TypeDeclarationSyntax)root.Members[0];
var methodDecl = (MethodDeclarationSyntax)typeDecl.Members[0];
var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree);
var speculatedCref = (TypeCrefSyntax)SyntaxFactory.ParseCref("object");
// TryGetSpeculativeSemanticModel
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(typeDecl.SpanStart, speculatedCref, out speculativeModel);
Assert.False(success);
success = model.TryGetSpeculativeSemanticModel(methodDecl.Body.SpanStart, speculatedCref, out speculativeModel);
Assert.False(success);
// GetSpeculativeSymbolInfo
var symbolInfo = model.GetSpeculativeSymbolInfo(methodDecl.Body.SpanStart, speculatedCref);
Assert.Null(symbolInfo.Symbol);
}
[WorkItem(731108, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/731108")]
[Fact]
public void Repro731108()
{
var source = @"
public class C
{
static void Main()
{
M(async x => x);
}
static void M(C c)
{
}
}
";
var comp = CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var syntax = tree.GetRoot().DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().Single().
Body.DescendantNodesAndSelf().OfType<IdentifierNameSyntax>().Single();
Assert.Equal("x", syntax.Identifier.ValueText);
var symbol = model.GetSymbolInfo(syntax).Symbol;
Assert.Equal(SymbolKind.Parameter, symbol.Kind);
Assert.Equal("x", symbol.Name);
Assert.Equal(TypeKind.Error, ((IParameterSymbol)symbol).Type.TypeKind);
}
[WorkItem(783566, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/783566")]
[Fact]
public void SpeculateAboutYieldStatement1()
{
var source = @"
class C
{
void M() // No way to infer iterator element type.
{
return;
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var position = source.IndexOf("return", StringComparison.Ordinal);
var yieldStatement = (YieldStatementSyntax)SyntaxFactory.ParseStatement("yield return 1;");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, yieldStatement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var info = speculativeModel.GetTypeInfo(yieldStatement.Expression);
Assert.Equal(SpecialType.System_Int32, info.Type.SpecialType);
Assert.Equal(TypeKind.Error, info.ConvertedType.TypeKind);
}
[WorkItem(783566, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/783566")]
[Fact]
public void SpeculateAboutYieldStatement2()
{
var source = @"
using System.Collections.Generic;
class C
{
IEnumerable<long> M() // Can infer iterator element type.
{
return null;
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var position = source.IndexOf("return", StringComparison.Ordinal);
var yieldStatement = (YieldStatementSyntax)SyntaxFactory.ParseStatement("yield return 1;");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, yieldStatement, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var info = speculativeModel.GetTypeInfo(yieldStatement.Expression);
Assert.Equal(SpecialType.System_Int32, info.Type.SpecialType);
Assert.Equal(SpecialType.System_Int64, info.ConvertedType.SpecialType);
}
[WorkItem(791794, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/791794")]
[Fact]
public void SpeculateAboutOmittedArraySizeInCref()
{
var source = @"
/// <see cref=""int""/>
class C
{
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var position = source.IndexOf("int", StringComparison.Ordinal);
var typeSyntax = SyntaxFactory.ParseTypeName("System.Collections.Generic.IEnumerable<C[]>");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, typeSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var omittedArraySize = typeSyntax.DescendantNodes().OfType<OmittedArraySizeExpressionSyntax>().Single();
var info = speculativeModel.GetSymbolInfo(omittedArraySize); // Used to throw NRE.
Assert.Null(info.Symbol);
Assert.Equal(CandidateReason.None, info.CandidateReason);
Assert.Equal(0, info.CandidateSymbols.Length);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_out()
{
var source = @"
class C
{
void M()
{
int x;
TakesOut(out x);
}
void TakesOut(out int x) { x = 0; }
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("TakesOut", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseStatement("TakesOut(out int x);");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, statementSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var method2 = statementSyntax.DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info2 = speculativeModel.GetSymbolInfo(method2);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_out2()
{
var source = @"
class C
{
void M()
{
int y;
TakesOut(out y);
}
void TakesOut(out int y) { y = 0; }
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("TakesOut", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseStatement("TakesOut(out int x);");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, statementSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var method2 = statementSyntax.DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info2 = speculativeModel.GetSymbolInfo(method2);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_out3()
{
var source = @"
class C
{
void M()
{
int x;
TakesOut(out x);
}
void TakesOut(out int x) { x = 0; }
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("TakesOut", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseExpression("TakesOut(out int x)");
var info2 = model.GetSpeculativeSymbolInfo(position, statementSyntax, SpeculativeBindingOption.BindAsExpression);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_out4()
{
var source = @"
class C
{
void M()
{
int y;
TakesOut(out y);
}
void TakesOut(out int y) { y = 0; }
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("TakesOut", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseStatement("{ TakesOut(out int x); }");
statementSyntax = ((BlockSyntax)statementSyntax).Statements[0];
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, statementSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var method2 = statementSyntax.DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info2 = speculativeModel.GetSymbolInfo(method2);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_pattern()
{
var source = @"
class C
{
void M(object o)
{
Method(o is string);
string s = o as string;
}
bool Method(bool b) => b;
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("Method", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseStatement("Method(o is string s);");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, statementSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var method2 = statementSyntax.DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info2 = speculativeModel.GetSymbolInfo(method2);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_pattern2()
{
var source = @"
class C
{
void M(object o)
{
Method(o is string);
string s2 = o as string;
}
bool Method(bool b) => b;
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("Method", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseStatement("Method(o is string s);");
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, statementSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var method2 = statementSyntax.DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info2 = speculativeModel.GetSymbolInfo(method2);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[WorkItem(14384, "https://github.com/dotnet/roslyn/issues/14384")]
[Fact]
public void SpeculateWithExpressionVariables_pattern3()
{
var source = @"
class C
{
void M(object o)
{
Method(o is string);
string s2 = o as string;
}
bool Method(bool b) => b;
}
";
var comp = CreateCompilationWithMscorlib40AndDocumentationComments(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var method1 = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
var info1 = model.GetSymbolInfo(method1);
Assert.NotNull(info1.Symbol);
var position = source.IndexOf("Method", StringComparison.Ordinal);
var statementSyntax = SyntaxFactory.ParseExpression("Method(o is string s)");
var info2 = model.GetSpeculativeSymbolInfo(position, statementSyntax, SpeculativeBindingOption.BindAsExpression);
Assert.NotNull(info2.Symbol);
Assert.Equal(info1.Symbol, info2.Symbol);
}
[Fact]
public void BindSpeculativeAttributeWithExpressionVariable_1()
{
new ObsoleteAttribute("goo");
var source =
@"using System;
class C { }";
var compilation = CreateCompilation(source);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var position = tree.GetText().ToString().IndexOf("class C {", StringComparison.Ordinal);
var attr2 = ParseAttributeSyntax("[ObsoleteAttribute(string.Empty is string s ? s : string.Empty)]");
var symbolInfo = model.GetSpeculativeSymbolInfo(position, attr2);
Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason);
Assert.Equal("System.ObsoleteAttribute..ctor(System.String message)", symbolInfo.Symbol.ToTestDisplayString());
}
[Fact]
public void BindSpeculativeAttributeWithExpressionVariable_2()
{
new ObsoleteAttribute("goo");
var source =
@"using System;
class C { }";
var compilation = CreateCompilation(source);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var position = tree.GetText().ToString().IndexOf("class C {", StringComparison.Ordinal);
var attr2 = ParseAttributeSyntax("[ObsoleteAttribute(string.Empty is string s ? s : string.Empty)]");
SemanticModel model2;
model.TryGetSpeculativeSemanticModel(position, attr2, out model2);
var symbolInfo = model2.GetSymbolInfo(attr2);
Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason);
Assert.Equal("System.ObsoleteAttribute..ctor(System.String message)", symbolInfo.Symbol.ToTestDisplayString());
}
private AttributeSyntax ParseAttributeSyntax(string source)
{
return SyntaxFactory.ParseCompilationUnit(source + " class X {}").Members.First().AsTypeDeclarationSyntax().AttributeLists.First().Attributes.First();
}
[WorkItem(784255, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/784255")]
[Fact]
public void Repro784255()
{
var source = @"
using System;
public class CategoryAttribute : Attribute
{
public CategoryAttribute(string s) { }
private CategoryAttribute() { }
}
struct S
{
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var position = source.IndexOf("struct", StringComparison.Ordinal);
var attributeSyntax = SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("Category"));
SemanticModel speculativeModel;
var success = model.TryGetSpeculativeSemanticModel(position, attributeSyntax, out speculativeModel);
Assert.True(success);
Assert.NotNull(speculativeModel);
var info = speculativeModel.GetSymbolInfo(attributeSyntax.Name);
}
[WorkItem(1015557, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1015557")]
[Fact(Skip = "1015557")]
public void GetSpeculativeSymbolInfoForGenericNameInCref()
{
var tree = CSharpSyntaxTree.ParseText(@"using System.Collections.Generic;
class Program
{
/// <summary>
/// <see cref=""System.Collections.Generic.List{T}.Contains(T)""/>
/// </summary>
static void Main()
{
}
}", CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose));
var compilation = CreateCompilation(tree);
var root = tree.GetCompilationUnitRoot();
var crefSyntax = root.DescendantNodes(descendIntoTrivia: true).OfType<QualifiedCrefSyntax>().Single();
var semanticModel = compilation.GetSemanticModel(tree);
var symbolInfo = semanticModel.GetSymbolInfo(crefSyntax.FindNode(new TextSpan(91, 34)));
var oldSymbol = symbolInfo.Symbol;
Assert.NotNull(oldSymbol);
Assert.Equal(SymbolKind.NamedType, oldSymbol.Kind);
Assert.Equal("System.Collections.Generic.List<T>", oldSymbol.ToTestDisplayString());
var speculatedName = (GenericNameSyntax)SyntaxFactory.GenericName("List{T}");
var speculativeSymbolInfo = semanticModel.GetSpeculativeSymbolInfo(crefSyntax.SpanStart, speculatedName, SpeculativeBindingOption.BindAsExpression);
var newSymbol = speculativeSymbolInfo.Symbol;
Assert.NotNull(newSymbol);
Assert.Equal(SymbolKind.NamedType, newSymbol.Kind);
Assert.Equal("System.Collections.Generic.List<T>", newSymbol.ToTestDisplayString());
Assert.False(((NamedTypeSymbol)newSymbol).TypeArguments().Single().IsErrorType());
Assert.True(newSymbol.Equals(oldSymbol));
}
[WorkItem(823791, "DevDiv")]
[Fact]
public void LambdaArgumentInBadCall_Constructor()
{
var source = @"
using System;
class Test
{
void M()
{
new Test(s => s.
}
Test(Action<string> a, int i) { }
}
";
CheckLambdaArgumentInBadCall(source);
}
[WorkItem(823791, "DevDiv")]
[Fact]
public void LambdaArgumentInBadCall_Method()
{
var source = @"
using System;
class Test
{
void M()
{
Method(s => s.
}
void Method(Action<string> a, int i) { }
}
";
CheckLambdaArgumentInBadCall(source);
}
[WorkItem(823791, "DevDiv")]
[Fact]
public void LambdaArgumentInBadCall_Indexer()
{
var source = @"
using System;
class Test
{
void M()
{
var t = this[s => s.
}
int this[Action<string> a, int i] { get { return 0; } }
}
";
CheckLambdaArgumentInBadCall(source);
}
[WorkItem(823791, "DevDiv")]
[Fact]
public void LambdaArgumentInBadCall_Delegate()
{
var source = @"
using System;
class Test
{
void M()
{
d(s => s.
}
Action<Action<string>, int> d = null;
}
";
CheckLambdaArgumentInBadCall(source);
}
[WorkItem(823791, "DevDiv")]
[Fact]
public void LambdaArgumentInBadCall_ConstructorInitializer()
{
var source = @"
using System;
class Test
{
protected Test(Action<string> a, int i) { }
}
class Derived : Test
{
Derived()
: base(s => s.
{
}
}
";
CheckLambdaArgumentInBadCall(source);
}
private static void CheckLambdaArgumentInBadCall(string source)
{
var comp = (Compilation)CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
Assert.NotEmpty(tree.GetDiagnostics());
var memberAccess = tree.GetRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single();
var identifier = (IdentifierNameSyntax)memberAccess.Expression;
Assert.Equal("s", identifier.Identifier.ValueText);
var stringType = comp.GetSpecialType(SpecialType.System_String);
var actionType = comp.GetWellKnownType(WellKnownType.System_Action_T).Construct(stringType);
var model = comp.GetSemanticModel(tree);
// Can't walk up to ArgumentListSyntax because indexers use BracketedArgumentListSyntax.
var expr = identifier.FirstAncestorOrSelf<ArgumentSyntax>().Parent.Parent;
var exprInfo = model.GetSymbolInfo(expr);
var firstParamType = ((ISymbol)exprInfo.CandidateSymbols.Single()).GetParameters().First().Type;
Assert.Equal(actionType, firstParamType);
var identifierInfo = model.GetTypeInfo(identifier);
Assert.Equal(stringType, identifierInfo.Type);
Assert.Equal(stringType, identifierInfo.ConvertedType);
}
[Fact, WorkItem(45825, "https://github.com/dotnet/roslyn/issues/45825")]
public void LambdaReturnSpeculation()
{
var comp = CreateCompilation(@"
class C
{
public static implicit operator C(string s) => null!;
C M()
{
string s = """";
System.Func<string> local = () =>
{
s.ToString();
return s;
};
local();
return null!;
}
}");
comp.VerifyDiagnostics(
);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var localFunctionBody = tree.GetRoot().DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
var typeInfo = model.GetTypeInfo(localFunctionBody.DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression!);
Assert.Equal("System.String", typeInfo.ConvertedType.ToTestDisplayString(includeNonNullable: false));
var @return = (ReturnStatementSyntax)SyntaxFactory.ParseStatement("return s;");
Assert.True(model.TryGetSpeculativeSemanticModel(localFunctionBody.Block!.Statements[0].SpanStart + 1, @return, out var specModel));
typeInfo = specModel!.GetTypeInfo(@return.Expression!);
// This behavior is broken. The return type here should be 'System.String' because we are speculating within the lambda.
// https://github.com/dotnet/roslyn/issues/45825
Assert.Equal("C", typeInfo.ConvertedType.ToTestDisplayString(includeNonNullable: false));
}
[WorkItem(850907, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/850907")]
[Fact]
public void ExtensionMethodViability()
{
var source = @"
static class Extensions
{
private static void ToString(this object o, int x)
{
o.ToString(1);
}
}
";
var comp = CreateCompilationWithMscorlib40AndSystemCore(source);
comp.VerifyDiagnostics();
var extensionMethod = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("Extensions").GetMember<MethodSymbol>("ToString");
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var callSyntax = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
var memberGroup = model.GetMemberGroup(callSyntax.Expression);
Assert.Contains(extensionMethod.ReduceExtensionMethod().ISymbol, memberGroup);
}
[WorkItem(849698, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/849698")]
[Fact]
public void LookupExternAlias()
{
var source = @"
extern alias Alias;
class C
{
static void Main()
{
Alias::C.M();
}
";
var libRef = CreateCompilation("", assemblyName: "lib").EmitToImageReference(aliases: ImmutableArray.Create("Alias"));
var comp = CreateCompilation(source, new[] { libRef });
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var syntax = tree.GetRoot().DescendantNodes().OfType<AliasQualifiedNameSyntax>().Single();
var symbol = model.LookupSymbols(syntax.SpanStart, name: "Alias").Single();
Assert.Equal("Alias", symbol.Name);
Assert.Equal(SymbolKind.Alias, symbol.Kind);
var target = (INamespaceSymbol)((IAliasSymbol)symbol).Target;
Assert.True(target.IsGlobalNamespace);
Assert.Equal("lib", target.ContainingAssembly.Name);
}
[Theory, MemberData(nameof(FileScopedOrBracedNamespace))]
public void LookupInNamespace(string ob, string cb)
{
var source = @"
namespace NS
" + ob + @"
class C
{
void M() { }
void M0() { }
}
" + cb + @"
";
var comp = CreateCompilation(source);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var methodDecl = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var endPosition = methodDecl.Body.OpenBraceToken.EndPosition;
var symbol = model.LookupSymbols(endPosition, name: "M0").Single();
Assert.Equal("void NS.C.M0()", symbol.ToTestDisplayString());
}
[WorkItem(1019366, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1019366")]
[WorkItem(273, "CodePlex")]
[ClrOnlyFact]
public void Bug1019366()
{
var source = @"
using System;
static class Program
{
static void Main()
{
short case1 = unchecked((short)65535.17567);
Console.WriteLine(case1);
int? case2 = (int?)5.5;
Console.WriteLine(case2);
int? case3 = (int?)5;
Console.WriteLine(case3);
}
}
";
var comp = (Compilation)CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
// The CodePlex bug indicates that this should return a constant value of -1. However, the specified
// value of this is explicitly "undefined", and differs from one host architecture to another.
// For determinism we make all undefined unchecked floating to integral conversions yield zero
// at compile-time. That may differ from the result at runtime depending on your runtime architecture.
// See https://github.com/dotnet/roslyn/issues/37527
var method = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single();
var init0 = method.Body.Statements[0].DescendantNodes().OfType<VariableDeclaratorSyntax>().Single().Initializer.Value;
var value0 = model.GetConstantValue(init0);
var typeInfo0 = model.GetTypeInfo(init0);
Assert.True(value0.HasValue);
Assert.Equal(0, (short)value0.Value);
Assert.True(typeInfo0.Type != null && typeInfo0.Type.SpecialType == SpecialType.System_Int16);
// The CodePlex bug indicates this should return a constant value of 5. While 'case2' should
// have that value it is not constant because of the nullable cast
var init1 = method.Body.Statements[2].DescendantNodes().OfType<VariableDeclaratorSyntax>().Single().Initializer.Value;
var value1 = model.GetConstantValue(init1);
var typeInfo1 = model.GetTypeInfo(init1);
var type1 = comp.GetSpecialType(SpecialType.System_Nullable_T).Construct(comp.GetSpecialType(SpecialType.System_Int32));
Assert.False(value1.HasValue);
Assert.True(typeInfo1.Type != null && typeInfo1.Type.Equals(type1));
var init2 = method.Body.Statements[4].DescendantNodes().OfType<VariableDeclaratorSyntax>().Single().Initializer.Value;
var value2 = model.GetConstantValue(init2);
var typeInfo2 = model.GetTypeInfo(init2);
var type2 = comp.GetSpecialType(SpecialType.System_Nullable_T).Construct(comp.GetSpecialType(SpecialType.System_Int32));
Assert.False(value2.HasValue);
Assert.True(typeInfo2.Type != null && typeInfo2.Type.Equals(type2));
var output = @"
0
5
5";
CompileAndVerify(compilation: comp, expectedOutput: output);
}
[Fact]
public void Regression01()
{
Regression(@"
using System;
class MyClass {
public protected int intI = 1;
public static int Main() {
return 1;
}
}"
);
}
[Fact]
public void Regression02()
{
Regression(@"
using System;
class Convert
{
public static void Main()
{
S s = new S();
}
}
"
);
}
[Fact]
public void Regression03()
{
Regression(@"
using System;
namespace Microsoft.Conformance.Expressions
{
using basic097LevelOne.basic097LevelTwo;
public class basic097I<A1>
{
public static int Method()
{
return 0;
}
}
namespace basic097LevelOne
{
namespace basic097LevelTwo
{
public class basic097I<A1>
{
}
}
}
}"
);
}
[Fact, WorkItem(1504, "https://github.com/dotnet/roslyn/issues/1504")]
public void ContainingSymbol02()
{
var source =
@"using System;
class C
{
static bool G<T>(Func<T> f) => true;
static void F()
{
Exception x1 = null;
try
{
G(() => x1);
}
catch (Exception x2) when (G(() => x2))
{
}
}
}";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source);
var model = compilation.GetSemanticModel(compilation.SyntaxTrees.Single());
for (var match = System.Text.RegularExpressions.Regex.Match(source, " => x"); match.Success; match = match.NextMatch())
{
var discarded = model.GetEnclosingSymbol(match.Index);
}
}
[Fact, WorkItem(1504, "https://github.com/dotnet/roslyn/issues/1504")]
public void ContainingSymbol03()
{
var source =
@"using System;
class C
{
static bool G<T>(Func<T> f) => true;
static void F()
{
Exception x1 = null, x2 = null;
do
{
G(() => x1);
}
while (G(() => x2));
}
}";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
for (var match = System.Text.RegularExpressions.Regex.Match(source, " => x"); match.Success; match = match.NextMatch())
{
var x = tree.GetRoot().FindToken(match.Index + 4).Parent;
var discarded = model.GetEnclosingSymbol(match.Index);
var disc = model.GetSymbolInfo(x);
}
}
[Fact, WorkItem(1504, "https://github.com/dotnet/roslyn/issues/1504")]
public void ContainingSymbol04()
{
var source =
@"using System;
class C
{
static bool G<T>(Func<T> f) => true;
static void F()
{
Exception x1 = null, x2 = null;
if (G(() => x1));
{
G(() => x2);
}
}
}";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source);
var model = compilation.GetSemanticModel(compilation.SyntaxTrees.Single());
var discarded1 = model.GetEnclosingSymbol(source.LastIndexOf(" => x"));
var discarded2 = model.GetEnclosingSymbol(source.IndexOf(" => x"));
}
[WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")]
[Fact]
public void ConstantValueOfInterpolatedString()
{
var source = @"
class Program
{
static void Main(string[] args)
{
Console.WriteLine($""Hello, world!"");
Console.WriteLine($""{DateTime.Now.ToString()}.{args[0]}"");
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var actual = tree.GetRoot().DescendantNodes().OfType<InterpolatedStringExpressionSyntax>().ToArray();
Assert.True(model.GetConstantValue(actual[0]).HasValue);
Assert.Equal("Hello, world!", model.GetConstantValue(actual[0]).Value);
Assert.False(model.GetConstantValue(actual[1]).HasValue);
}
[Fact]
public void ConstantValueOfInterpolatedStringComplex()
{
var source = @"
class Program
{
static void Main(string[] args)
{
const string S1 = $""Number 3"";
Console.WriteLine($""{""Level 5""} {S1}"");
Console.WriteLine($""Level {5} {S1}"");
}
void M(string S1 = $""Testing"", Namae n = null)
{
if (n is Namae { X : $""ConstantInterpolatedString""}){
switch(S1){
case $""Level 5"":
break;
case $""Radio Noise"":
goto case $""Level 5"";
}
}
S1 = S0;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var actual = tree.GetRoot().DescendantNodes().OfType<InterpolatedStringExpressionSyntax>().ToArray();
Assert.Equal(@"$""Number 3""", actual[0].ToString());
Assert.Equal("Number 3", model.GetConstantValue(actual[0]).Value);
Assert.Equal(@"$""{""Level 5""} {S1}""", actual[1].ToString());
Assert.Equal("Level 5 Number 3", model.GetConstantValue(actual[1]).Value);
Assert.False(model.GetConstantValue(actual[2]).HasValue);
Assert.Equal(@"$""Testing""", actual[3].ToString());
Assert.Equal("Testing", model.GetConstantValue(actual[3]).Value);
Assert.Equal(@"$""ConstantInterpolatedString""", actual[4].ToString());
Assert.Equal("ConstantInterpolatedString", model.GetConstantValue(actual[4]).Value);
Assert.Equal(@"$""Level 5""", actual[5].ToString());
Assert.Equal("Level 5", model.GetConstantValue(actual[5]).Value);
Assert.Equal(@"$""Radio Noise""", actual[6].ToString());
Assert.Equal("Radio Noise", model.GetConstantValue(actual[6]).Value);
Assert.Equal(@"$""Level 5""", actual[7].ToString());
Assert.Equal("Level 5", model.GetConstantValue(actual[7]).Value);
}
[WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")]
[Fact]
public void ConstantValueOfRawInterpolatedString()
{
var source = @"
class Program
{
static void Main(string[] args)
{
Console.WriteLine($""""""Hello, world!"""""");
Console.WriteLine($""""""{DateTime.Now.ToString()}.{args[0]}"""""");
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var actual = tree.GetRoot().DescendantNodes().OfType<InterpolatedStringExpressionSyntax>().ToArray();
Assert.True(model.GetConstantValue(actual[0]).HasValue);
Assert.Equal("Hello, world!", model.GetConstantValue(actual[0]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[0]).Type.SpecialType);
Assert.False(model.GetConstantValue(actual[1]).HasValue);
}
[WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")]
[Fact]
public void ConstantValueOfRawInterpolatedString2()
{
var source = @"
class Program
{
static void Main(string[] args)
{
Console.WriteLine($""""""{0}.{true}"""""");
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var actual = tree.GetRoot().DescendantNodes().OfType<LiteralExpressionSyntax>().ToArray();
Assert.True(model.GetConstantValue(actual[0]).HasValue);
Assert.Equal(0, model.GetConstantValue(actual[0]).Value);
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(actual[0]).Type.SpecialType);
Assert.True(model.GetConstantValue(actual[1]).HasValue);
Assert.Equal(true, model.GetConstantValue(actual[1]).Value);
Assert.Equal(SpecialType.System_Boolean, model.GetTypeInfo(actual[1]).Type.SpecialType);
}
[WorkItem(976, "https://github.com/dotnet/roslyn/issues/976")]
[Fact]
public void ConstantValueOfRawInterpolatedString3()
{
var source = @"
class Program
{
static void Main(string[] args)
{
Console.WriteLine($""""""{null}"""""");
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var actual = tree.GetRoot().DescendantNodes().OfType<LiteralExpressionSyntax>().ToArray();
Assert.True(model.GetConstantValue(actual[0]).HasValue);
Assert.Null(model.GetConstantValue(actual[0]).Value);
Assert.Null(model.GetTypeInfo(actual[0]).Type);
}
[Fact]
public void ConstantValueOfRawInterpolatedStringComplex()
{
var source = @"
class Program
{
static void Main(string[] args)
{
const string S1 = $""""""Number 3"""""";
Console.WriteLine($""""""{""""""Level 5""""""} {S1}"""""");
Console.WriteLine($""""""Level {5} {S1}"""""");
}
void M(string S1 = $""""""Testing"""""", Namae n = null)
{
if (n is Namae { X : $""""""ConstantInterpolatedString""""""}){
switch(S1){
case $""""""Level 5"""""":
break;
case $""""""Radio Noise"""""":
goto case $""""""Level 5"""""";
}
}
S1 = S0;
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var actual = tree.GetRoot().DescendantNodes().OfType<InterpolatedStringExpressionSyntax>().ToArray();
Assert.Equal(@"$""""""Number 3""""""", actual[0].ToString());
Assert.Equal("Number 3", model.GetConstantValue(actual[0]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[0]).Type.SpecialType);
Assert.Equal(@"$""""""{""""""Level 5""""""} {S1}""""""", actual[1].ToString());
Assert.Equal("Level 5 Number 3", model.GetConstantValue(actual[1]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[1]).Type.SpecialType);
Assert.False(model.GetConstantValue(actual[2]).HasValue);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[2]).Type.SpecialType);
Assert.Equal(@"$""""""Testing""""""", actual[3].ToString());
Assert.Equal("Testing", model.GetConstantValue(actual[3]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[3]).Type.SpecialType);
Assert.Equal(@"$""""""ConstantInterpolatedString""""""", actual[4].ToString());
Assert.Equal("ConstantInterpolatedString", model.GetConstantValue(actual[4]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[4]).Type.SpecialType);
Assert.Equal(@"$""""""Level 5""""""", actual[5].ToString());
Assert.Equal("Level 5", model.GetConstantValue(actual[5]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[5]).Type.SpecialType);
Assert.Equal(@"$""""""Radio Noise""""""", actual[6].ToString());
Assert.Equal("Radio Noise", model.GetConstantValue(actual[6]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[6]).Type.SpecialType);
Assert.Equal(@"$""""""Level 5""""""", actual[7].ToString());
Assert.Equal("Level 5", model.GetConstantValue(actual[7]).Value);
Assert.Equal(SpecialType.System_String, model.GetTypeInfo(actual[7]).Type.SpecialType);
}
[WorkItem(814, "https://github.com/dotnet/roslyn/issues/814")]
[Fact]
public void TypeOfDynamic()
{
var source = @"
using System;
using System.Dynamic;
class Program
{
static void Main(string[] args)
{
dynamic a = 5;
}
}
";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe);
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var typeSyntax = SyntaxFactory.ParseTypeName("dynamic");
int spanStart = source.IndexOf("dynamic a = 5;");
var dynamicType = model.GetSpeculativeTypeInfo(spanStart, typeSyntax, SpeculativeBindingOption.BindAsTypeOrNamespace);
Assert.Equal(TypeKind.Dynamic, dynamicType.Type.TypeKind);
}
[Fact]
public void IsAccessible()
{
var source =
@"using System;
class A
{
public int X;
protected int Y;
private protected int Z;
}
class B : A
{
void Goo()
{
// in B.Goo
}
// in B class level
int field;
}
class C
{
void Goo()
{
// in C.Goo
}
}
namespace N
{
// in N
}";
var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular7_2);
compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).Verify();
var tree = compilation.SyntaxTrees[0];
var text = tree.GetText().ToString();
var semanticModel = compilation.GetSemanticModel(tree);
int positionInB = text.IndexOf("in B class level");
int positionInBGoo = text.IndexOf("in B.Goo");
int positionInCGoo = text.IndexOf("in C.Goo");
int positionInN = text.IndexOf("in N");
var globalNs = compilation.GlobalNamespace;
var classA = (NamedTypeSymbol)globalNs.GetMembers("A").Single();
var fieldX = (IFieldSymbol)classA.GetMembers("X").Single().ISymbol;
var fieldY = (IFieldSymbol)classA.GetMembers("Y").Single().ISymbol;
var fieldZ = (IFieldSymbol)classA.GetMembers("Z").Single().ISymbol;
Assert.True(semanticModel.IsAccessible(positionInN, fieldX));
Assert.False(semanticModel.IsAccessible(positionInN, fieldY));
Assert.False(semanticModel.IsAccessible(positionInN, fieldZ));
Assert.True(semanticModel.IsAccessible(positionInB, fieldX));
Assert.True(semanticModel.IsAccessible(positionInB, fieldY));
Assert.True(semanticModel.IsAccessible(positionInB, fieldZ));
Assert.True(semanticModel.IsAccessible(positionInBGoo, fieldX));
Assert.True(semanticModel.IsAccessible(positionInBGoo, fieldY));
Assert.True(semanticModel.IsAccessible(positionInBGoo, fieldZ));
Assert.True(semanticModel.IsAccessible(positionInCGoo, fieldX));
Assert.False(semanticModel.IsAccessible(positionInCGoo, fieldY));
Assert.False(semanticModel.IsAccessible(positionInCGoo, fieldZ));
}
[Fact, WorkItem(40201, "https://github.com/dotnet/roslyn/issues/40201")]
public void SpeculativeModelConflictingNameUnary_DeclarationPattern()
{
var source = @"
using System.Threading;
class C
{
void Test()
{
var ct = CancellationToken.None;
if (!(this.Helper(CancellationToken.None) is string nonDiscard))
{
}
}
object Helper(CancellationToken ct) { return null; }
}
";
var replacementSource = @"
if (!(this.Helper(CancellationToken.None) is var nonDiscard))
{
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3);
var syntaxTree = comp.SyntaxTrees[0];
var root = syntaxTree.GetRoot();
var model = comp.GetSemanticModel(syntaxTree);
var ifStatement = root.DescendantNodes().OfType<IfStatementSyntax>().Single();
var replacementIfStatement = (IfStatementSyntax)SyntaxFactory.ParseStatement(replacementSource);
Assert.True(model.TryGetSpeculativeSemanticModel(ifStatement.SpanStart, replacementIfStatement, out var specModel));
var originalTypeInfo = model.GetTypeInfo(ifStatement.Condition);
Assert.Equal(SpecialType.System_Boolean, originalTypeInfo.Type.SpecialType);
var speculativeTypeInfo = specModel.GetTypeInfo(replacementIfStatement.Condition);
Assert.Equal(SpecialType.System_Boolean, speculativeTypeInfo.Type.SpecialType);
}
[Fact, WorkItem(52013, "https://github.com/dotnet/roslyn/issues/52013")]
public void NameOf_ArgumentDoesNotExist()
{
var source = @"
using System.Diagnostics;
public partial class C
{
[Conditional(nameof(DEBUG))]
void M() { }
";
var comp = CreateCompilation(source);
var method = (IMethodSymbol)comp.GetTypeByMetadataName("C").GetMembers("M").Single().GetPublicSymbol();
var attribute = method.GetAttributes().Single();
Assert.Equal("DEBUG", attribute.ConstructorArguments[0].Value);
var tree = comp.SyntaxTrees.Single();
var root = tree.GetRoot();
var model = comp.GetSemanticModel(tree);
Assert.Equal("DEBUG", model.GetConstantValue(root.DescendantNodes().OfType<InvocationExpressionSyntax>().Single()));
}
[Theory, CombinatorialData, WorkItem(54437, "https://github.com/dotnet/roslyn/issues/54437")]
public void TestVarTuple(NullableContextOptions nullableContextOption)
{
var source = """
var (a1, b1) = ("", 0);
""";
var options = WithNullable(TestOptions.DebugExe, nullableContextOption);
var comp = CreateCompilation(source, options: options, parseOptions: TestOptions.Regular9);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
var declarationExpression = root.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single();
var varNode = declarationExpression.Type;
var varTypeInfo = model.GetTypeInfo(varNode);
var declarationExpressionTypeInfo = model.GetTypeInfo(declarationExpression);
assertTypeInfo(varTypeInfo);
Assert.Equal(varTypeInfo, declarationExpressionTypeInfo);
var varSymbolInfo = model.GetSymbolInfo(varNode);
assertSymbolInfo(varSymbolInfo);
var declarationExpressionSymbolInfo = model.GetSymbolInfo(declarationExpression);
Assert.Equal(SymbolInfo.None, declarationExpressionSymbolInfo);
static void assertTypeInfo(TypeInfo typeInfo)
{
Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.Nullability.Annotation);
Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.ConvertedNullability.Annotation);
Assert.NotNull(typeInfo.Type);
Assert.NotNull(typeInfo.ConvertedType);
Assert.Equal(typeInfo.Type, typeInfo.ConvertedType);
var type = (INamedTypeSymbol)typeInfo.Type;
Assert.True(type.IsTupleType);
Assert.Equal(2, type.Arity);
Assert.Equal(2, type.TupleElements.Length);
Assert.Equal(SpecialType.System_String, type.TupleElements[0].Type.SpecialType);
Assert.Equal(SpecialType.System_Int32, type.TupleElements[1].Type.SpecialType);
}
static void assertSymbolInfo(SymbolInfo symbolInfo)
{
Assert.False(symbolInfo.IsEmpty);
Assert.Empty(symbolInfo.CandidateSymbols);
Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason);
Assert.Equal("(System.String a1, System.Int32 b1)", symbolInfo.Symbol.ToTestDisplayString());
}
}
[Theory, CombinatorialData, WorkItem(54437, "https://github.com/dotnet/roslyn/issues/54437")]
public void TestVarTupleWithVarTypeInScope(NullableContextOptions nullableContextOption)
{
var source = """
var (a1, b1) = ("", 0);
class @var { }
""";
var options = WithNullable(TestOptions.DebugExe, nullableContextOption);
var comp = CreateCompilation(source, options: options, parseOptions: TestOptions.Regular9);
comp.VerifyDiagnostics(
// (1,5): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'.
// var (a1, b1) = ("", 0);
Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "(a1, b1)").WithLocation(1, 5),
// (1,17): error CS0029: Cannot implicitly convert type 'string' to 'var'
// var (a1, b1) = ("", 0);
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "var").WithLocation(1, 17),
// (1,21): error CS0029: Cannot implicitly convert type 'int' to 'var'
// var (a1, b1) = ("", 0);
Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "var").WithLocation(1, 21));
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var root = tree.GetCompilationUnitRoot();
var declarationExpression = root.DescendantNodes().OfType<DeclarationExpressionSyntax>().Single();
var varNode = declarationExpression.Type;
var varTypeInfo = model.GetTypeInfo(varNode);
var declarationExpressionTypeInfo = model.GetTypeInfo(declarationExpression);
assertTypeInfoForVar(varTypeInfo);
assertTypeInfoForDeclarationExpression(declarationExpressionTypeInfo);
var varSymbolInfo = model.GetSymbolInfo(varNode);
assertSymbolInfo(varSymbolInfo);
var declarationExpressionSymbolInfo = model.GetSymbolInfo(declarationExpression);
Assert.Equal(SymbolInfo.None, declarationExpressionSymbolInfo);
static void assertTypeInfoForVar(TypeInfo typeInfo)
{
Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.Nullability.Annotation);
Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.ConvertedNullability.Annotation);
Assert.NotNull(typeInfo.Type);
Assert.NotNull(typeInfo.ConvertedType);
Assert.Equal(typeInfo.Type, typeInfo.ConvertedType);
var type = (INamedTypeSymbol)typeInfo.Type;
Assert.Equal("var", type.ToTestDisplayString());
Assert.Equal(TypeKind.Class, type.TypeKind);
}
static void assertTypeInfoForDeclarationExpression(TypeInfo typeInfo)
{
Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.Nullability.Annotation);
Assert.Equal(CodeAnalysis.NullableAnnotation.None, typeInfo.ConvertedNullability.Annotation);
Assert.NotNull(typeInfo.Type);
Assert.NotNull(typeInfo.ConvertedType);
Assert.Equal(typeInfo.Type, typeInfo.ConvertedType);
var type = (INamedTypeSymbol)typeInfo.Type;
Assert.True(type.IsTupleType);
Assert.Equal(2, type.Arity);
Assert.Equal(2, type.TupleElements.Length);
Assert.Equal(TypeKind.Class, type.TupleElements[0].Type.TypeKind);
Assert.Equal(TypeKind.Class, type.TupleElements[1].Type.TypeKind);
}
static void assertSymbolInfo(SymbolInfo symbolInfo)
{
Assert.False(symbolInfo.IsEmpty);
Assert.Empty(symbolInfo.CandidateSymbols);
Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason);
Assert.Equal("var", symbolInfo.Symbol.ToTestDisplayString());
}
}
[Fact]
public void EqualsOnAliasSymbolWithNullContainingAssembly_NotEquals()
{
var text = @"
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute("".NETCoreApp, Version = v6.0"", FrameworkDisplayName = """")]
";
var alias1 = getGlobalAlias(CreateCompilation(text));
var alias2 = getGlobalAlias(CreateCompilation(text));
Assert.Equal("<global namespace>", alias1.ContainingSymbol.ToTestDisplayString());
Assert.Null(alias1.ContainingAssembly);
Assert.False(alias1.Equals(alias2));
static IAliasSymbol getGlobalAlias(CSharpCompilation compilation)
{
var tree = compilation.SyntaxTrees.Single();
var node = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(ident => ident.Identifier.Text == "global").Single();
return compilation.GetSemanticModel(tree).GetAliasInfo(node);
}
}
[Fact]
public void EqualsOnAliasSymbolWithNullContainingAssembly_Equals()
{
var text = @"
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute("".NETCoreApp, Version = v6.0"", FrameworkDisplayName = """")]
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute("".NETCoreApp, Version = v6.0"", FrameworkDisplayName = """")]
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var nodes = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(ident => ident.Identifier.Text == "global").ToArray();
var model = compilation.GetSemanticModel(tree);
var alias1 = model.GetAliasInfo(nodes[0]);
var alias2 = model.GetAliasInfo(nodes[1]);
Assert.Equal("<global namespace>", alias1.ContainingSymbol.ToTestDisplayString());
Assert.Null(alias1.ContainingAssembly);
Assert.True(alias1.Equals(alias2));
}
[Fact]
public void OutVarInRankSpecifier_LocalDeclaration()
{
var text = @"
int[M(out var x)] i = null;
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "M");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Theory]
[InlineData("out")]
[InlineData("ref")]
public void OutVarInRankSpecifier_LocalFunctionParameter(string modifier)
{
var text = $$"""
void M({{modifier}} Type[M2(out object y)])
{
}
""";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "M2");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Fact]
public void OutVarInRankSpecifier_LocalFunctionReturn()
{
var text = @"
Type[M2(out object y)] M()
{
}
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "M2");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66806")]
public void OutVarInRankSpecifier()
{
var text = @"
bool TryGet(out [NotNullWhen( object x, out object y, out object z)
{
return true;
}
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "NotNullWhen");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Fact]
public void OutVarInRankSpecifier_TypeConstraint()
{
var text = @"
void M<T>() where T : int[M2(out var x)]
{
}
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "M2");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Fact]
public void OutVarInRankSpecifier_MethodParameter()
{
var text = @"
class C
{
void M(out Type[M2(out object y)])
{
}
}
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "M2");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Fact]
public void OutVarInRankSpecifier_PrimaryConstructorParameter()
{
var text = @"
class C(out Type[M2(out object y)])
{
}
";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(i => i.Identifier.Text == "M2");
var model = compilation.GetSemanticModel(tree);
Assert.Null(model.GetAliasInfo(identifier));
}
[Fact]
public void CommonPreprocessingSymbolProperties()
{
var text = """
#if NET5_0_OR_GREATER
#endif
""";
var compilation = CreateCompilation(text);
var tree = compilation.SyntaxTrees.Single();
var identifier = tree.GetRoot().DescendantNodes(descendIntoTrivia: true).OfType<IdentifierNameSyntax>().First();
var model = compilation.GetSemanticModel(tree);
var preprocessingSymbol = model.GetPreprocessingSymbolInfo(identifier).Symbol;
Assert.NotNull(preprocessingSymbol);
Assert.Equal("NET5_0_OR_GREATER", preprocessingSymbol.Name);
Assert.True(preprocessingSymbol.CanBeReferencedByName);
}
#region "regression helper"
private void Regression(string text)
{
var tree = Parse(text);
var compilation = CreateCompilation(tree);
var model = compilation.GetSemanticModel(tree);
var exprSynList = new List<ExpressionSyntax>();
GetExpressionSyntax(tree.GetCompilationUnitRoot(), exprSynList);
// Console.WriteLine("Roslyn Symbol Info: ");
foreach (var exprSyn in exprSynList)
{
var expr = exprSyn.ToString();
// Console.WriteLine("Expression: " + expr);
var type = model.GetTypeInfo(exprSyn).Type;
// Console.WriteLine("Type: " + type);
// Console.WriteLine();
}
}
private static void GetExpressionSyntax(SyntaxNode node, List<ExpressionSyntax> exprSynList)
{
if (node is ExpressionSyntax)
exprSynList.Add(node as ExpressionSyntax);
foreach (var child in node.ChildNodesAndTokens())
if (child.IsNode)
GetExpressionSyntax(child.AsNode(), exprSynList);
}
#endregion
}
}
|