/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Symbol/Symbols/Source/DeclaringSyntaxNodeTests.cs
766 строк
30 KB
Julien Couvreur
Warn for multiple blank lines in source (#65451)
17 ноя 2022, 22:55
Не верифицирован
17 ноя 2022, 22:55
a8824e8
Код
Авторство
О чём код?
// 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.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Source { public class DeclaringSyntaxNodeTests : CSharpTestBase { // Check that the given symbol has the expected number of declaring syntax nodes. // and that each declared node goes back to the given symbol. private ImmutableArray<SyntaxReference> CheckDeclaringSyntaxNodes(Compilation compilation, ISymbol symbol, int expectedNumber) { var declaringReferences = symbol.DeclaringSyntaxReferences; Assert.Equal(expectedNumber, declaringReferences.Length); if (expectedNumber == 0) { Assert.True(!symbol.GetSymbol().IsFromCompilation((CSharpCompilation)compilation) || symbol.IsImplicitlyDeclared, "non-implicitly declares source symbol should have declaring location"); } else { Assert.True(symbol.GetSymbol().IsFromCompilation((CSharpCompilation)compilation) || symbol.GetSymbol() is MergedNamespaceSymbol, "symbol with declaration should be in source, except for merged namespaces"); Assert.False(symbol.IsImplicitlyDeclared); foreach (var node in declaringReferences.Select(d => d.GetSyntax())) { // Make sure GetDeclaredSymbol gets back to the symbol for each node. SyntaxTree tree = node.SyntaxTree; SemanticModel model = compilation.GetSemanticModel(tree); Assert.Equal(symbol.OriginalDefinition, model.GetDeclaredSymbol(node)); } } return declaringReferences; } private ImmutableArray<SyntaxReference> CheckDeclaringSyntaxNodesIncludingParameters(Compilation compilation, ISymbol symbol, int expectedNumber) { var nodes = CheckDeclaringSyntaxNodes(compilation, symbol, expectedNumber); var meth = symbol as IMethodSymbol; if (meth != null) { foreach (IParameterSymbol p in meth.Parameters) CheckDeclaringSyntaxNodes(compilation, p, meth.GetSymbol().IsAccessor() ? 0 : expectedNumber); } var prop = symbol as IPropertySymbol; if (prop != null) { foreach (IParameterSymbol p in prop.Parameters) CheckDeclaringSyntaxNodes(compilation, p, expectedNumber); } return nodes; } // Check that the given symbol has the expected number of declaring syntax nodes. // and that the syntax has the expected kind. Does NOT test GetDeclaringSymbol private ImmutableArray<SyntaxReference> CheckDeclaringSyntaxNodesWithoutGetDeclaredSymbol(Compilation compilation, ISymbol symbol, int expectedNumber, SyntaxKind expectedSyntaxKind) { var declaringReferences = symbol.DeclaringSyntaxReferences; Assert.Equal(expectedNumber, declaringReferences.Length); if (expectedNumber == 0) { Assert.True(!symbol.GetSymbol().IsFromCompilation((CSharpCompilation)compilation) || symbol.IsImplicitlyDeclared, "non-implicitly declares source symbol should have declaring location"); } else { Assert.True(symbol.GetSymbol().IsFromCompilation((CSharpCompilation)compilation) || symbol.GetSymbol() is MergedNamespaceSymbol, "symbol with declaration should be in source, except for merged namespaces"); if (symbol.Kind == SymbolKind.Namespace && ((INamespaceSymbol)symbol).IsGlobalNamespace) { Assert.True(symbol.IsImplicitlyDeclared); } else { Assert.False(symbol.IsImplicitlyDeclared); } foreach (var node in declaringReferences.Select(d => d.GetSyntax())) { // Make sure each node is of the expected kind. Assert.Equal(expectedSyntaxKind, node.Kind()); } } return declaringReferences; } private void AssertDeclaringSyntaxNodes(Symbol symbol, CSharpCompilation compilation, params SyntaxNode[] expectedSyntaxNodes) { int expectedNumber = expectedSyntaxNodes.Length; var declaringReferences = symbol.DeclaringSyntaxReferences; Assert.Equal(expectedNumber, declaringReferences.Length); if (expectedNumber == 0) { Assert.True(!symbol.IsFromCompilation(compilation) || symbol.IsImplicitlyDeclared, "non-implicitly declares source symbol should have declaring location"); } else { Assert.True(symbol.IsFromCompilation(compilation) || symbol is MergedNamespaceSymbol, "symbol with declaration should be in source, except for merged namespaces"); Assert.False(symbol.IsImplicitlyDeclared); for (int i = 0; i < expectedNumber; i++) { Assert.Same(expectedSyntaxNodes[i], declaringReferences[i].GetSyntax()); } } } private void CheckDeclaringSyntax<TNode>(CSharpCompilation comp, SyntaxTree tree, string name, SymbolKind kind) where TNode : CSharpSyntaxNode { var model = comp.GetSemanticModel(tree); string code = tree.GetText().ToString(); int position = code.IndexOf(name, StringComparison.Ordinal); var node = tree.GetRoot().FindToken(position).Parent.FirstAncestorOrSelf<TNode>(); var sym = model.GetDeclaredSymbol(node); Assert.Equal(kind, sym.Kind); Assert.Equal(name, sym.Name); CheckDeclaringSyntaxNodes(comp, sym, 1); } private void CheckLambdaDeclaringSyntax<TNode>(CSharpCompilation comp, SyntaxTree tree, string textToSearchFor) where TNode : ExpressionSyntax { var model = comp.GetSemanticModel(tree); string code = tree.GetText().ToString(); int position = code.IndexOf(textToSearchFor, StringComparison.Ordinal); var node = tree.GetCompilationUnitRoot().FindToken(position).Parent.FirstAncestorOrSelf<TNode>(); var sym = model.GetSymbolInfo(node).Symbol as IMethodSymbol; Assert.NotNull(sym); Assert.Equal(MethodKind.AnonymousFunction, sym.MethodKind); var nodes = CheckDeclaringSyntaxNodesWithoutGetDeclaredSymbol(comp, sym, 1, node.Kind()); Assert.Equal(nodes[0].GetSyntax(), node); foreach (IParameterSymbol p in sym.Parameters) { CheckDeclaringSyntaxNodes(comp, p, 1); } } [Theory, MemberData(nameof(FileScopedOrBracedNamespace))] public void SourceNamedTypeDeclaringSyntax(string ob, string cb) { var text = @" namespace N1 " + ob + @" class C1<T> { class Nested<U> {} delegate int NestedDel(string s); } public struct S1 { C1<int> f; } internal interface I1 {} enum E1 { Red } delegate void D1(int i); " + cb + @" "; var comp = (Compilation)CreateCompilation(text); var global = comp.GlobalNamespace; var n1 = global.GetMembers("N1").Single() as INamespaceSymbol; Assert.False(n1.IsImplicitlyDeclared); Assert.True(comp.SourceModule.GlobalNamespace.IsImplicitlyDeclared); var types = n1.GetTypeMembers(); foreach (ISymbol s in types) { CheckDeclaringSyntaxNodes(comp, s, 1); } var c1 = n1.GetTypeMembers("C1").Single() as INamedTypeSymbol; var s1 = n1.GetTypeMembers("S1").Single() as INamedTypeSymbol; var f = s1.GetMembers("f").Single() as IFieldSymbol; CheckDeclaringSyntaxNodes(comp, f.Type, 1); // constructed type C1<int>. // Nested types. foreach (ISymbol s in c1.GetTypeMembers()) { CheckDeclaringSyntaxNodes(comp, s, 1); } } [Fact] public void NonSourceTypeDeclaringSyntax() { var text = @" namespace N1 { class C1 { object o; int i; System.Collections.Generic.List<string> lst; dynamic dyn; C1[] arr; C1[,] arr2d; ErrType err; ConsErrType<object> consErr; } } "; var comp = (Compilation)CreateCompilation(text); var global = comp.GlobalNamespace; var n1 = global.GetMembers("N1").Single() as INamespaceSymbol; var c1 = n1.GetTypeMembers("C1").Single() as INamedTypeSymbol; // Check types of each field in C1; should not have declaring syntax node. foreach (IFieldSymbol f in c1.GetMembers().OfType<IFieldSymbol>()) { CheckDeclaringSyntaxNodes(comp, f.Type, 0); } } [Fact] public void AnonTypeDeclaringSyntax() { var text = @" class C1 { void f() { var a1 = new { a = 5, b = ""hi"" }; var a2 = new {}; } } "; var tree = Parse(text); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree); var global = comp.GlobalNamespace; int posA1 = text.IndexOf("a1", StringComparison.Ordinal); var declaratorA1 = tree.GetCompilationUnitRoot().FindToken(posA1).Parent.FirstAncestorOrSelf<VariableDeclaratorSyntax>(); var localA1 = (ILocalSymbol)model.GetDeclaredSymbol(declaratorA1); var localA1Type = localA1.Type; Assert.True(localA1Type.IsAnonymousType); // Anonymous types don't support GetDeclaredSymbol. CheckDeclaringSyntaxNodesWithoutGetDeclaredSymbol(comp, localA1Type, 1, SyntaxKind.AnonymousObjectCreationExpression); // Check members of the anonymous type. foreach (ISymbol memb in localA1Type.GetMembers()) { int expectedDeclaringNodes = 0; if (memb is IPropertySymbol) { expectedDeclaringNodes = 1; // declared property } CheckDeclaringSyntaxNodes(comp, memb, expectedDeclaringNodes); } } [WorkItem(543829, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543829")] [Fact] public void AnonymousTypeSymbolWithExplicitNew() { var text = @" class C1 { void f() { var q = new { y = 2 }; var x = new { y = 5 }; var z = x; } } "; var tree = Parse(text); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree); var global = comp.GlobalNamespace; // check 'q' int posQ = text.IndexOf('q'); var declaratorQ = tree.GetCompilationUnitRoot().FindToken(posQ).Parent.FirstAncestorOrSelf<VariableDeclaratorSyntax>(); CheckAnonymousType(model, (ILocalSymbol)model.GetDeclaredSymbol(declaratorQ), (AnonymousObjectCreationExpressionSyntax)declaratorQ.Initializer.Value); // check 'x' int posX = text.IndexOf('x'); var declaratorX = tree.GetCompilationUnitRoot().FindToken(posX).Parent.FirstAncestorOrSelf<VariableDeclaratorSyntax>(); CheckAnonymousType(model, (ILocalSymbol)model.GetDeclaredSymbol(declaratorX), (AnonymousObjectCreationExpressionSyntax)declaratorX.Initializer.Value); // check 'z' --> 'x' int posZ = text.IndexOf('z'); var declaratorZ = tree.GetCompilationUnitRoot().FindToken(posZ).Parent.FirstAncestorOrSelf<VariableDeclaratorSyntax>(); CheckAnonymousType(model, (ILocalSymbol)model.GetDeclaredSymbol(declaratorZ), (AnonymousObjectCreationExpressionSyntax)declaratorX.Initializer.Value); } private void CheckAnonymousType(SemanticModel model, ILocalSymbol local, AnonymousObjectCreationExpressionSyntax anonObjectCreation) { var localType = local.Type; Assert.True(localType.IsAnonymousType); // IsImplicitlyDeclared: Return false. The new { } clause // serves as the declaration. Assert.False(localType.IsImplicitlyDeclared); // DeclaringSyntaxNodes: Return the AnonymousObjectCreationExpression from the particular // anonymous type definition that flowed to this usage. AssertDeclaringSyntaxNodes(((CSharp.Symbols.PublicModel.Symbol)localType).UnderlyingSymbol, (CSharpCompilation)model.Compilation, anonObjectCreation); // SemanticModel.GetDeclaredSymbol: Return this symbol when applied to the // AnonymousObjectCreationExpression in the new { } declaration. var symbol = model.GetDeclaredSymbol(anonObjectCreation); Assert.NotNull(symbol); Assert.Equal<ISymbol>(localType, symbol); Assert.Same(localType.DeclaringSyntaxReferences[0].GetSyntax(), symbol.DeclaringSyntaxReferences[0].GetSyntax()); // Locations: Return the Span of that particular // AnonymousObjectCreationExpression's NewKeyword. Assert.Equal(1, localType.Locations.Length); Assert.Equal(localType.Locations[0], anonObjectCreation.NewKeyword.GetLocation()); // Members check int propIndex = 0; foreach (var member in localType.GetMembers()) { if (member.Kind == SymbolKind.Property) { // Equals: Return true when comparing same-named members of // structurally-equivalent anonymous type symbols. var members = symbol.GetMembers(member.Name); Assert.Equal(1, members.Length); Assert.Equal(member, members[0]); // IsImplicitlyDeclared: Return false. The goo = bar clause in // the new { } clause serves as the declaration. Assert.False(member.IsImplicitlyDeclared); // DeclaringSyntaxNodes: Return the AnonymousObjectMemberDeclarator from the // particular property definition that flowed to this usage. var propertyInitializer = anonObjectCreation.Initializers[propIndex]; Assert.Equal(1, member.DeclaringSyntaxReferences.Length); Assert.Same(propertyInitializer, member.DeclaringSyntaxReferences[0].GetSyntax()); // SemanticModel.GetDeclaredSymbol: Return this symbol when applied to its new { } // declaration's AnonymousObjectMemberDeclarator. var propSymbol = model.GetDeclaredSymbol(propertyInitializer); Assert.Equal<ISymbol>(member, propSymbol); Assert.Same(propertyInitializer, propSymbol.DeclaringSyntaxReferences[0].GetSyntax()); // Locations: Return the Span of that particular // AnonymousObjectMemberDeclarator's IdentifierToken. Assert.Equal(1, member.Locations.Length); Assert.Equal(member.Locations[0], propertyInitializer.NameEquals.Name.GetLocation()); propIndex++; } } } [Fact] public void NamespaceDeclaringSyntax() { var text = @" namespace N1 { namespace N2 { namespace N3 {} } } namespace N1.N2 { namespace N3 {} } namespace System {} "; var comp = (Compilation)CreateCompilation(text); var global = comp.GlobalNamespace; var system = global.GetMembers("System").Single() as INamespaceSymbol; var n1 = global.GetMembers("N1").Single() as INamespaceSymbol; var n2 = n1.GetMembers("N2").Single() as INamespaceSymbol; var n3 = n2.GetMembers("N3").Single() as INamespaceSymbol; CheckDeclaringSyntaxNodes(comp, n2, 2); CheckDeclaringSyntaxNodes(comp, n3, 2); CheckDeclaringSyntaxNodes(comp, system, 1); // Can't use GetDeclaredSymbol for N1 or global. CheckDeclaringSyntaxNodesWithoutGetDeclaredSymbol(comp, n1, 2, SyntaxKind.NamespaceDeclaration); CheckDeclaringSyntaxNodesWithoutGetDeclaredSymbol(comp, global, 1, SyntaxKind.CompilationUnit); } [Theory, MemberData(nameof(FileScopedOrBracedNamespace))] public void TypeParameterDeclaringSyntax(string ob, string cb) { var text = @" using System; using System.Collections.Generic; namespace N1 " + ob + @" class C1<T, U> { class C2<W> { public C1<int, string>.C2<W> f1; public void m<R, S>(); } class C3<W> { IEnumerable<U> f2; Goo<Bar> f3; } } class M { } " + cb + @" "; var comp = (Compilation)CreateCompilation(text); var global = comp.GlobalNamespace; var n1 = global.GetMembers("N1").Single() as INamespaceSymbol; var c1 = n1.GetTypeMembers("C1").Single() as INamedTypeSymbol; var c2 = c1.GetTypeMembers("C2").Single() as INamedTypeSymbol; var c3 = c1.GetTypeMembers("C3").Single() as INamedTypeSymbol; foreach (ISymbol s in c1.TypeParameters) { CheckDeclaringSyntaxNodes(comp, s, 1); } foreach (IFieldSymbol f in c2.GetMembers().OfType<IFieldSymbol>()) { foreach (ITypeParameterSymbol tp in ((INamedTypeSymbol)f.Type).TypeParameters) { CheckDeclaringSyntaxNodes(comp, tp, 1); } } foreach (IMethodSymbol m in c2.GetMembers().OfType<IMethodSymbol>()) { foreach (ITypeParameterSymbol tp in m.TypeParameters) { CheckDeclaringSyntaxNodes(comp, tp, 1); } } foreach (IFieldSymbol f in c3.GetMembers().OfType<IFieldSymbol>()) { foreach (ITypeParameterSymbol tp in ((INamedTypeSymbol)f.Type).TypeParameters) { CheckDeclaringSyntaxNodes(comp, tp, 0); } } } [Fact] public void MemberDeclaringSyntax() { var text = @" using System; using System.Collections.Generic; namespace N1 { enum E1 {Red, Blue = 5, Green }; class C1<T> { C1<int> t, w, x; const int q = 4, r = 7; C1(int i) {} static C1() {} int m(T t, int y = 3) { return 3; } int P {get { return 0; } set {}} abstract int Prop2 {get; set; } int Prop3 {get; set; } string this[int i] {get { return ""; } set {}} abstract string this[int i, int j] {get; set;} event EventHandler ev1; event EventHandler ev2 { add {} remove {} } } class C2<U> { static int x = 7; } } "; var comp = (Compilation)CreateCompilation(text); var global = comp.GlobalNamespace; var n1 = global.GetMembers("N1").Single() as INamespaceSymbol; var c1 = n1.GetTypeMembers("C1").Single() as INamedTypeSymbol; var c2 = n1.GetTypeMembers("C2").Single() as INamedTypeSymbol; var e1 = n1.GetTypeMembers("E1").Single() as INamedTypeSymbol; foreach (ISymbol memb in e1.GetMembers()) { if (memb.Kind == SymbolKind.Method && ((IMethodSymbol)memb).MethodKind == MethodKind.Constructor) CheckDeclaringSyntaxNodesIncludingParameters(comp, memb, 0); // implicit constructor else CheckDeclaringSyntaxNodesIncludingParameters(comp, memb, 1); } var ev1 = c1.GetMembers("ev1").Single() as IEventSymbol; var prop3 = c1.GetMembers("Prop3").Single() as IPropertySymbol; foreach (ISymbol memb in c1.GetMembers()) { int expectedDeclaringNodes = 1; if (memb is IMethodSymbol) { var meth = (IMethodSymbol)memb; if (meth.AssociatedSymbol != null && meth.AssociatedSymbol.OriginalDefinition.Equals(ev1)) expectedDeclaringNodes = 0; // implicit accessor. } if (memb is IFieldSymbol) { var fld = (IFieldSymbol)memb; if (fld.AssociatedSymbol != null && fld.AssociatedSymbol.OriginalDefinition.Equals(prop3)) expectedDeclaringNodes = 0; // auto-prop backing field. } CheckDeclaringSyntaxNodesIncludingParameters(comp, memb, expectedDeclaringNodes); } var fieldT = c1.GetMembers("t").Single() as IFieldSymbol; var constructedC1 = fieldT.Type; foreach (ISymbol memb in constructedC1.GetMembers()) { int expectedDeclaringNodes = 1; if (memb is IMethodSymbol) { var meth = (IMethodSymbol)memb; if (meth.AssociatedSymbol != null && meth.AssociatedSymbol.OriginalDefinition.Equals(ev1)) expectedDeclaringNodes = 0; // implicit accessor. } if (memb is IFieldSymbol) { var fld = (IFieldSymbol)memb; if (fld.AssociatedSymbol != null && fld.AssociatedSymbol.OriginalDefinition.Equals(prop3)) expectedDeclaringNodes = 0; // auto-prop backing field. } CheckDeclaringSyntaxNodesIncludingParameters(comp, memb, expectedDeclaringNodes); } foreach (ISymbol memb in c2.GetMembers()) { if (memb.Kind == SymbolKind.Method) CheckDeclaringSyntaxNodesIncludingParameters(comp, memb, 0); } } [Fact] public void LocalDeclaringSyntax() { var text = @" using System; using System.Collections.Generic; class C1 { void m() { int loc1, loc2 = 4, loc3; const int loc4 = 6, loc5 = 7; using (IDisposable loc6 = goo()) {} for (int loc7 = 0; loc7 < 10; ++loc7) {} foreach (int loc8 in new int[] {1,3,4}) {} } } "; var tree = Parse(text); var comp = CreateCompilation(tree); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc1", SymbolKind.Local); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc2", SymbolKind.Local); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc3", SymbolKind.Local); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc4", SymbolKind.Local); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc5", SymbolKind.Local); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc6", SymbolKind.Local); CheckDeclaringSyntax<VariableDeclaratorSyntax>(comp, tree, "loc7", SymbolKind.Local); CheckDeclaringSyntax<ForEachStatementSyntax>(comp, tree, "loc8", SymbolKind.Local); } [Fact] public void LabelDeclaringSyntax() { var text = @" using System; using System.Collections.Generic; class C1 { void m(int i) { lab1: ; lab2: lab3: Console.WriteLine(); switch (i) { case 4: case 3: break; default: break; } } } "; var tree = Parse(text); var comp = CreateCompilation(tree); CheckDeclaringSyntax<LabeledStatementSyntax>(comp, tree, "lab1", SymbolKind.Label); CheckDeclaringSyntax<LabeledStatementSyntax>(comp, tree, "lab2", SymbolKind.Label); CheckDeclaringSyntax<LabeledStatementSyntax>(comp, tree, "lab3", SymbolKind.Label); CheckDeclaringSyntax<SwitchLabelSyntax>(comp, tree, "case 4:", SymbolKind.Label); CheckDeclaringSyntax<SwitchLabelSyntax>(comp, tree, "case 3:", SymbolKind.Label); CheckDeclaringSyntax<SwitchLabelSyntax>(comp, tree, "default", SymbolKind.Label); } [Fact] public void AliasDeclaringSyntax() { var text = @" using System; using System.Collections.Generic; using ConsoleAlias=System.Console; using ListOfIntAlias=System.Collections.Generic.List<int>; namespace N1 { using GooAlias=Con; } "; var tree = Parse(text); var comp = CreateCompilation(tree); CheckDeclaringSyntax<UsingDirectiveSyntax>(comp, tree, "ConsoleAlias", SymbolKind.Alias); CheckDeclaringSyntax<UsingDirectiveSyntax>(comp, tree, "ListOfIntAlias", SymbolKind.Alias); CheckDeclaringSyntax<UsingDirectiveSyntax>(comp, tree, "GooAlias", SymbolKind.Alias); } [Fact] public void RangeVariableDeclaringSyntax() { var text = @" using System; using System.Collections.Generic; using System.Linq; class C { void f() { IEnumerable<int> a = null; var y1 = from range1 in a let range2 = a.ToString() select range1 into range3 select range3 + 1; var y2 = from range4 in a join range5 in a on range4.ToString() equals range5.ToString() into range6 select range6; } } "; var tree = Parse(text); var comp = CreateCompilation(tree); CheckDeclaringSyntax<QueryClauseSyntax>(comp, tree, "range1", SymbolKind.RangeVariable); CheckDeclaringSyntax<QueryClauseSyntax>(comp, tree, "range2", SymbolKind.RangeVariable); CheckDeclaringSyntax<QueryContinuationSyntax>(comp, tree, "range3", SymbolKind.RangeVariable); CheckDeclaringSyntax<QueryClauseSyntax>(comp, tree, "range4", SymbolKind.RangeVariable); CheckDeclaringSyntax<QueryClauseSyntax>(comp, tree, "range5", SymbolKind.RangeVariable); CheckDeclaringSyntax<JoinIntoClauseSyntax>(comp, tree, "range6", SymbolKind.RangeVariable); } [Fact] public void LambdaDeclaringSyntax() { var text = @" using System; using System.Collections.Generic; using System.Linq; class C { void f() { Func<int, int, int> f1 = (a,b) => /*1*/ a + b; Func<int, int, int> f1 = a => /*2*/ a + 1; Func<int, int, int> f1 = delegate(int a, int b) /*3*/ { return a + b; }; } } "; var tree = Parse(text); var comp = CreateCompilation(tree); CheckLambdaDeclaringSyntax<ParenthesizedLambdaExpressionSyntax>(comp, tree, "/*1*/"); CheckLambdaDeclaringSyntax<SimpleLambdaExpressionSyntax>(comp, tree, "/*2*/"); CheckLambdaDeclaringSyntax<AnonymousMethodExpressionSyntax>(comp, tree, "/*3*/"); } /// <summary> /// Symbol location order should be preserved when trees /// are replaced in the compilation. /// </summary> [WorkItem(11015, "https://github.com/dotnet/roslyn/issues/11015")] [Fact] public void PreserveLocationOrderOnReplaceSyntaxTree() { var source0 = Parse("namespace N { partial class C { } } namespace N0 { } class C0 { }"); var source1 = Parse("namespace N { partial class C { } } namespace N1 { } class C1 { }"); var source2 = Parse("namespace N { struct S { } }"); var source3 = Parse("namespace N { partial class C { } } namespace N3 { } class C3 { }"); var comp0 = CreateCompilation(new[] { source0, source1, source2, source3 }); comp0.VerifyDiagnostics(); Assert.Equal(new[] { source0, source1, source2, source3 }, comp0.SyntaxTrees); // Location order of partial class should match SyntaxTrees order. var locations = comp0.GetMember<NamedTypeSymbol>("N.C").Locations; Assert.Equal(new[] { source0, source1, source3 }, locations.Select(l => l.SourceTree)); // AddSyntaxTrees will add to the end. var source4 = Parse("namespace N { partial class C { } } namespace N4 { } class C4 { }"); var comp1 = comp0.AddSyntaxTrees(source4); locations = comp1.GetMember<NamedTypeSymbol>("N.C").Locations; Assert.Equal(new[] { source0, source1, source3, source4 }, locations.Select(l => l.SourceTree)); // ReplaceSyntaxTree should preserve location order. var comp2 = comp0.ReplaceSyntaxTree(source1, source4); locations = comp2.GetMember<NamedTypeSymbol>("N.C").Locations; Assert.Equal(new[] { source0, source4, source3 }, locations.Select(l => l.SourceTree)); // NamespaceNames and TypeNames do not match SyntaxTrees order. // This is expected. Assert.Equal(new[] { "", "N3", "N0", "N", "", "N4", "N" }, comp2.Declarations.NamespaceNames.ToArray()); Assert.Equal(new[] { "C3", "C0", "S", "C", "C4", "C" }, comp2.Declarations.TypeNames.ToArray()); // RemoveSyntaxTrees should preserve order of remaining trees. var comp3 = comp2.RemoveSyntaxTrees(source0); locations = comp3.GetMember<NamedTypeSymbol>("N.C").Locations; Assert.Equal(new[] { source4, source3 }, locations.Select(l => l.SourceTree)); } } }