File: Symbols\SymbolExtensionTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Symbol\Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests)
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Test.Utilities;
using System;
using System.Linq;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
{
    public class SymbolExtensionTests : CSharpTestBase
    {
        [Fact]
        public void HasNameQualifier()
        {
            var source =
@"class C { }
namespace N
{
    class C { }
    namespace NA
    {
        class C { }
        namespace NB
        {
            class C { }
        }
    }
}
namespace NA
{
    class C { }
    namespace NA
    {
        class C { }
    }
    namespace NB
    {
        class C { }
    }
}
namespace NB
{
    class C { }
}";
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics();
            var namespaceNames = new[]
            {
                "",
                ".",
                "N",
                "NA",
                "NB",
                "n",
                "AN",
                "NAB",
                "N.",
                ".NA",
                ".NB",
                "N.N",
                "N.NA",
                "N.NB",
                "N..NB",
                "N.NA.NA",
                "N.NA.NB",
                "NA.N",
                "NA.NA",
                "NA.NB",
                "NA.NA.NB",
                "NA.NB.NB",
            };
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("C"), "");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("N.C"), "N");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("N.NA.C"), "N.NA");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("N.NA.NB.C"), "N.NA.NB");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("NA.C"), "NA");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("NA.NA.C"), "NA.NA");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("NA.NB.C"), "NA.NB");
            HasNameQualifierCore(namespaceNames, compilation.GetMember<NamedTypeSymbol>("NB.C"), "NB");
        }
 
        [Fact]
        public void VisitType_AnonymousDelegate()
        {
            var source = @"
void F<T>(T t)
{
    var f = (ref T x) => 0;
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugDll);
            var tree = compilation.SyntaxTrees.Single();
            var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().First(id => id.Identifier.Text == "var");
            var model = compilation.GetSemanticModel(tree);
            var anonymousType = model.GetSymbolInfo(identifier).Symbol.GetSymbol<TypeSymbol>();
 
            Assert.True(anonymousType.ContainsTypeParameter());
        }
 
        [Fact]
        public void VisitType_AnonymousDelegateWithAnonymousClass()
        {
            var source = @"
void F<T>(T t)
{
    var f = (ref int x) => new { t };
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugDll);
            var tree = compilation.SyntaxTrees.Single();
            var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().First(id => id.Identifier.Text == "var");
            var model = compilation.GetSemanticModel(tree);
            var anonymousType = model.GetSymbolInfo(identifier).Symbol.GetSymbol<TypeSymbol>();
 
            Assert.True(anonymousType.ContainsTypeParameter());
        }
 
        [Fact]
        public void VisitType_AnonymousClass()
        {
            var source = @"
void F<T>(T t)
{
    var f = new { t };
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugDll);
            var tree = compilation.SyntaxTrees.Single();
            var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().First(id => id.Identifier.Text == "var");
            var model = compilation.GetSemanticModel(tree);
            var anonymousType = model.GetSymbolInfo(identifier).Symbol.GetSymbol<TypeSymbol>();
 
            Assert.True(anonymousType.ContainsTypeParameter());
        }
 
        [Fact]
        public void VisitType_AnonymousClassWithAnonymousDelegate()
        {
            var source = @"
void F<T>(T t)
{
    var f = (ref int x) => t;
    var g = new { f };
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugDll);
            var tree = compilation.SyntaxTrees.Single();
            var identifier = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Last(id => id.Identifier.Text == "var");
            var model = compilation.GetSemanticModel(tree);
            var anonymousType = model.GetSymbolInfo(identifier).Symbol.GetSymbol<TypeSymbol>();
 
            Assert.True(anonymousType.ContainsTypeParameter());
        }
 
        [Fact]
        public void VisitType_CustomModifiers()
        {
            var ilSource = @"
.class public auto ansi beforefieldinit C1`1<T>
    extends System.Object
{
    // Methods
    .method public hidebysig static 
        string Method () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 6 (0x6)
        .maxstack 8
 
        IL_0000: ldstr ""Method""
        IL_0005: ret
    } // end of method C1`1::Method
 
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2057
        // Code size 7 (0x7)
        .maxstack 8
 
        IL_0000: ldarg.0
        IL_0001: call instance void System.Object::.ctor()
        IL_0006: ret
    } // end of method C1`1::.ctor
 
} // end of class C1`1
 
.class public auto ansi beforefieldinit C2`1<T>
    extends System.Object
{
    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2057
        // Code size 7 (0x7)
        .maxstack 8
 
        IL_0000: ldarg.0
        IL_0001: call instance void System.Object::.ctor()
        IL_0006: ret
    } // end of method C2`1::.ctor
 
} // end of class C2`1
 
.class public auto ansi beforefieldinit C3`1<T>
    extends class C1`1<int32 modopt(class C2`1<!T>)>
{
    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x205f
        // Code size 7 (0x7)
        .maxstack 8
 
        IL_0000: ldarg.0
        IL_0001: call instance void class C1`1<int32>::.ctor()
        IL_0006: ret
    } // end of method C3`1::.ctor
 
} // end of class C3`1
";
 
            var source = @"
class Test
{
    static void Main()
    {
        M<int>();
    }
 
    static void M<G>()
    {
        System.Func<string> x = C3<G>.Method;
        System.Console.WriteLine(x());
    }
}
";
            var compilation = CreateCompilationWithIL(source, ilSource, options: TestOptions.ReleaseExe);
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
            var method = model.GetSymbolInfo(tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "Method").Single()).Symbol.GetSymbol<MethodSymbol>();
 
            AssertEx.Equal("System.String C1<System.Int32 modopt(C2<G>)>.Method()", method.ToTestDisplayString());
 
            var typeParameters = PooledHashSet<TypeParameterSymbol>.GetInstance();
            try
            {
                method.ContainingType.VisitType(static (typeSymbol, typeParameters, _) =>
                {
                    if (typeSymbol is TypeParameterSymbol typeParameter)
                    {
                        typeParameters.Add(typeParameter);
                    }
 
                    return false;
                },
                typeParameters, visitCustomModifiers: true);
 
                var typeParameter = typeParameters.Single();
                Assert.Equal("G", typeParameter.Name);
                Assert.Equal("M", typeParameter.ContainingSymbol.Name);
            }
            finally
            {
                typeParameters.Free();
            }
        }
 
        private void HasNameQualifierCore(string[] namespaceNames, NamedTypeSymbol type, string expectedName)
        {
            Assert.True(Array.IndexOf(namespaceNames, expectedName) >= 0);
            foreach (var namespaceName in namespaceNames)
            {
                Assert.Equal(namespaceName == expectedName, type.HasNameQualifier(namespaceName));
            }
        }
    }
}