File: Symbols\Metadata\PE\BaseTypeResolution.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 System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using CSReferenceManager = Microsoft.CodeAnalysis.CSharp.CSharpCompilation.ReferenceManager;
using System.Reflection.Metadata;
using Basic.Reference.Assemblies;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE
{
    public class BaseTypeResolution : CSharpTestBase
    {
        [Fact]
        public void Test1()
        {
            var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib);
 
            TestBaseTypeResolutionHelper1(assembly);
 
            var assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[]
            {
                TestReferences.SymbolsTests.MDTestLib1,
                TestReferences.SymbolsTests.MDTestLib2,
                Net40.References.mscorlib
            });
 
            TestBaseTypeResolutionHelper2(assemblies);
 
            assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[]
            {
                TestReferences.SymbolsTests.MDTestLib1,
                TestReferences.SymbolsTests.MDTestLib2
            });
 
            // TestBaseTypeResolutionHelper3(assemblies); // TODO(alekseyt): this test is not valid.  See email of 7/23/2010 for explanation.
 
            assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[]
            {
                TestReferences.SymbolsTests.MultiModule.Assembly,
                TestReferences.SymbolsTests.MultiModule.Consumer
            });
 
            TestBaseTypeResolutionHelper4(assemblies);
        }
 
        private void TestBaseTypeResolutionHelper1(AssemblySymbol assembly)
        {
            var module0 = assembly.Modules[0];
 
            var sys = module0.GlobalNamespace.GetMembers("System");
            var collections = ((NamespaceSymbol)sys[0]).GetMembers("Collections");
            var generic = ((NamespaceSymbol)collections[0]).GetMembers("Generic");
            var dictionary = ((NamespaceSymbol)generic[0]).GetMembers("Dictionary");
            var @base = ((NamedTypeSymbol)dictionary[0]).BaseType();
 
            AssertBaseType(@base, "System.Object");
            Assert.Null(@base.BaseType());
 
            var concurrent = ((NamespaceSymbol)collections[0]).GetMembers("Concurrent");
 
            var orderablePartitioners = ((NamespaceSymbol)concurrent[0]).GetMembers("OrderablePartitioner");
            NamedTypeSymbol orderablePartitioner = null;
 
            foreach (var p in orderablePartitioners)
            {
                var t = p as NamedTypeSymbol;
 
                if ((object)t != null && t.Arity == 1)
                {
                    orderablePartitioner = t;
                    break;
                }
            }
 
            @base = orderablePartitioner.BaseType();
 
            AssertBaseType(@base, "System.Collections.Concurrent.Partitioner<TSource>");
            Assert.Same(((NamedTypeSymbol)@base).TypeArguments()[0], orderablePartitioner.TypeParameters[0]);
 
            var partitioners = ((NamespaceSymbol)concurrent[0]).GetMembers("Partitioner");
            NamedTypeSymbol partitioner = null;
 
            foreach (var p in partitioners)
            {
                var t = p as NamedTypeSymbol;
 
                if ((object)t != null && t.Arity == 0)
                {
                    partitioner = t;
                    break;
                }
            }
 
            Assert.NotNull(partitioner);
        }
 
        private void TestBaseTypeResolutionHelper2(AssemblySymbol[] assemblies)
        {
            var module1 = assemblies[0].Modules[0];
            var module2 = assemblies[1].Modules[0];
 
            var varTC2 = module1.GlobalNamespace.GetTypeMembers("TC2").Single();
            var varTC3 = module1.GlobalNamespace.GetTypeMembers("TC3").Single();
            var varTC4 = module1.GlobalNamespace.GetTypeMembers("TC4").Single();
 
            AssertBaseType(varTC2.BaseType(), "C1<TC2_T1>.C2<TC2_T2>");
            AssertBaseType(varTC3.BaseType(), "C1<TC3_T1>.C3");
            AssertBaseType(varTC4.BaseType(), "C1<TC4_T1>.C3.C4<TC4_T2>");
 
            var varC1 = module1.GlobalNamespace.GetTypeMembers("C1").Single();
            AssertBaseType(varC1.BaseType(), "System.Object");
            Assert.Equal(0, varC1.Interfaces().Length);
 
            var varTC5 = module2.GlobalNamespace.GetTypeMembers("TC5").Single();
            var varTC6 = module2.GlobalNamespace.GetTypeMembers("TC6").Single();
            var varTC7 = module2.GlobalNamespace.GetTypeMembers("TC7").Single();
            var varTC8 = module2.GlobalNamespace.GetTypeMembers("TC8").Single();
            var varTC9 = varTC6.GetTypeMembers("TC9").Single();
 
            AssertBaseType(varTC5.BaseType(), "C1<TC5_T1>.C2<TC5_T2>");
            AssertBaseType(varTC6.BaseType(), "C1<TC6_T1>.C3");
            AssertBaseType(varTC7.BaseType(), "C1<TC7_T1>.C3.C4<TC7_T2>");
            AssertBaseType(varTC8.BaseType(), "C1<System.Type>");
            AssertBaseType(varTC9.BaseType(), "TC6<TC6_T1>");
 
            var varCorTypes = module2.GlobalNamespace.GetMembers("CorTypes").OfType<NamespaceSymbol>().Single();
 
            var varCorTypes_Derived = varCorTypes.GetTypeMembers("Derived").Single();
            AssertBaseType(varCorTypes_Derived.BaseType(),
                           "CorTypes.NS.Base<System.Boolean, System.SByte, System.Byte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.UInt64, System.Single, System.Double, System.Char, System.String, System.IntPtr, System.UIntPtr, System.Object>");
 
            var varCorTypes_Derived1 = varCorTypes.GetTypeMembers("Derived1").Single();
            AssertBaseType(varCorTypes_Derived1.BaseType(),
                           "CorTypes.Base<System.Int32[], System.Double[,]>");
 
            var varI101 = module1.GlobalNamespace.GetTypeMembers("I101").Single();
            var varI102 = module1.GlobalNamespace.GetTypeMembers("I102").Single();
 
            var varC203 = module1.GlobalNamespace.GetTypeMembers("C203").Single();
            Assert.Equal(1, varC203.Interfaces().Length);
            Assert.Same(varI101, varC203.Interfaces()[0]);
 
            var varC204 = module1.GlobalNamespace.GetTypeMembers("C204").Single();
            Assert.Equal(2, varC204.Interfaces().Length);
            Assert.Same(varI101, varC204.Interfaces()[0]);
            Assert.Same(varI102, varC204.Interfaces()[1]);
        }
 
        /* private void TestBaseTypeResolutionHelper3(AssemblySymbol[] assemblies)
        {
            var module1 = assemblies[0].Modules[0];
            var module2 = assemblies[1].Modules[0];
 
            var varCorTypes = module2.GlobalNamespace.GetMembers("CorTypes").OfType<NamespaceSymbol>().Single();
 
            var varCorTypes_Derived = varCorTypes.GetTypeMembers("Derived").Single();
            AssertBaseType(varCorTypes_Derived.BaseType(),
                           "CorTypes.NS.Base<System.Boolean,System.SByte,System.Byte,System.Int16,System.UInt16,System.Int32,System.UInt32,System.Int64,System.UInt64,System.Single,System.Double,System.Char,System.String,System.IntPtr,System.UIntPtr,System.Object>");
 
            foreach (var arg in varCorTypes_Derived.BaseType().TypeArguments())
            {
                Assert.IsAssignableFrom<MissingMetadataTypeSymbol>(arg);
            }
        } */
 
        private void TestBaseTypeResolutionHelper4(AssemblySymbol[] assemblies)
        {
            var module1 = assemblies[0].Modules[0];
            var module2 = assemblies[0].Modules[1];
            var module3 = assemblies[0].Modules[2];
            var module0 = assemblies[1].Modules[0];
 
            var derived1 = module0.GlobalNamespace.GetTypeMembers("Derived1").Single();
            var base1 = derived1.BaseType();
 
            var derived2 = module0.GlobalNamespace.GetTypeMembers("Derived2").Single();
            var base2 = derived2.BaseType();
 
            var derived3 = module0.GlobalNamespace.GetTypeMembers("Derived3").Single();
            var base3 = derived3.BaseType();
 
            AssertBaseType(base1, "Class1");
            AssertBaseType(base2, "Class2");
            AssertBaseType(base3, "Class3");
 
            Assert.Same(base1, module1.GlobalNamespace.GetTypeMembers("Class1").Single());
            Assert.Same(base2, module2.GlobalNamespace.GetTypeMembers("Class2").Single());
            Assert.Same(base3, module3.GlobalNamespace.GetTypeMembers("Class3").Single());
 
            return;
        }
 
        internal static void AssertBaseType(TypeSymbol @base, string name)
        {
            Assert.NotEqual(SymbolKind.ErrorType, @base.Kind);
            Assert.Equal(name, @base.ToTestDisplayString());
        }
 
        [Fact]
        public void Test2()
        {
            var assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[]
                                    {
                                        TestReferences.SymbolsTests.DifferByCase.Consumer,
                                        TestReferences.SymbolsTests.DifferByCase.TypeAndNamespaceDifferByCase
                                    });
 
            var module0 = assemblies[0].Modules[0] as PEModuleSymbol;
            var module1 = assemblies[1].Modules[0] as PEModuleSymbol;
 
            var bases = new HashSet<NamedTypeSymbol>();
 
            var localTC1 = module0.GlobalNamespace.GetTypeMembers("TC1").Single();
            var base1 = localTC1.BaseType();
            bases.Add(base1);
            Assert.NotEqual(SymbolKind.ErrorType, base1.Kind);
            Assert.Equal("SomeName.Dummy", base1.ToTestDisplayString());
 
            var localTC2 = module0.GlobalNamespace.GetTypeMembers("TC2").Single();
            var base2 = localTC2.BaseType();
            bases.Add(base2);
            Assert.NotEqual(SymbolKind.ErrorType, base2.Kind);
            Assert.Equal("somEnamE", base2.ToTestDisplayString());
 
            var localTC3 = module0.GlobalNamespace.GetTypeMembers("TC3").Single();
            var base3 = localTC3.BaseType();
            bases.Add(base3);
            Assert.NotEqual(SymbolKind.ErrorType, base3.Kind);
            Assert.Equal("somEnamE1", base3.ToTestDisplayString());
 
            var localTC4 = module0.GlobalNamespace.GetTypeMembers("TC4").Single();
            var base4 = localTC4.BaseType();
            bases.Add(base4);
            Assert.NotEqual(SymbolKind.ErrorType, base4.Kind);
            Assert.Equal("SomeName1", base4.ToTestDisplayString());
 
            var localTC5 = module0.GlobalNamespace.GetTypeMembers("TC5").Single();
            var base5 = localTC5.BaseType();
            bases.Add(base5);
            Assert.NotEqual(SymbolKind.ErrorType, base5.Kind);
            Assert.Equal("somEnamE2.OtherName", base5.ToTestDisplayString());
 
            var localTC6 = module0.GlobalNamespace.GetTypeMembers("TC6").Single();
            var base6 = localTC6.BaseType();
            bases.Add(base6);
            Assert.NotEqual(SymbolKind.ErrorType, base6.Kind);
            Assert.Equal("SomeName2.OtherName", base6.ToTestDisplayString());
 
            var localTC7 = module0.GlobalNamespace.GetTypeMembers("TC7").Single();
            var base7 = localTC7.BaseType();
            bases.Add(base7);
            Assert.NotEqual(SymbolKind.ErrorType, base7.Kind);
            Assert.Equal("NestingClass.somEnamE3", base7.ToTestDisplayString());
 
            var localTC8 = module0.GlobalNamespace.GetTypeMembers("TC8").Single();
            var base8 = localTC8.BaseType();
            bases.Add(base8);
            Assert.NotEqual(SymbolKind.ErrorType, base8.Kind);
            Assert.Equal("NestingClass.SomeName3", base8.ToTestDisplayString());
 
            Assert.Equal(8, bases.Count);
 
            Assert.Equal(base1, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base1).Handle]);
            Assert.Equal(base2, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base2).Handle]);
            Assert.Equal(base3, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base3).Handle]);
            Assert.Equal(base4, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base4).Handle]);
            Assert.Equal(base5, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base5).Handle]);
            Assert.Equal(base6, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base6).Handle]);
            Assert.Equal(base7, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base7).Handle]);
            Assert.Equal(base8, module1.TypeHandleToTypeMap[((PENamedTypeSymbol)base8).Handle]);
 
            Assert.Equal(base1, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC1).Handle)]);
            Assert.Equal(base2, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC2).Handle)]);
            Assert.Equal(base3, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC3).Handle)]);
            Assert.Equal(base4, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC4).Handle)]);
            Assert.Equal(base5, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC5).Handle)]);
            Assert.Equal(base6, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC6).Handle)]);
            Assert.Equal(base7, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC7).Handle)]);
            Assert.Equal(base8, module0.TypeRefHandleToTypeMap[(TypeReferenceHandle)module0.Module.GetBaseTypeOfTypeOrThrow(((PENamedTypeSymbol)localTC8).Handle)]);
 
            var assembly1 = (MetadataOrSourceAssemblySymbol)assemblies[1];
 
            Assert.Equal(base1, assembly1.CachedTypeByEmittedName(base1.ToTestDisplayString()));
            Assert.Equal(base2, assembly1.CachedTypeByEmittedName(base2.ToTestDisplayString()));
            Assert.Equal(base3, assembly1.CachedTypeByEmittedName(base3.ToTestDisplayString()));
            Assert.Equal(base4, assembly1.CachedTypeByEmittedName(base4.ToTestDisplayString()));
            Assert.Equal(base5, assembly1.CachedTypeByEmittedName(base5.ToTestDisplayString()));
            Assert.Equal(base6, assembly1.CachedTypeByEmittedName(base6.ToTestDisplayString()));
 
            Assert.Equal(base7.ContainingType, assembly1.CachedTypeByEmittedName(base7.ContainingType.ToTestDisplayString()));
 
            Assert.Equal(7, assembly1.EmittedNameToTypeMapCount);
        }
 
        [Fact]
        public void Test3()
        {
            var mscorlibRef = Net40.References.mscorlib;
 
            var c1 = CSharpCompilation.Create("Test", references: new MetadataReference[] { mscorlibRef });
 
            Assert.Equal("System.Object", ((SourceModuleSymbol)c1.Assembly.Modules[0]).GetCorLibType(SpecialType.System_Object).ToTestDisplayString());
 
            var localMTTestLib1Ref = TestReferences.SymbolsTests.V1.MTTestLib1.dll;
 
            var c2 = CSharpCompilation.Create("Test2", references: new MetadataReference[] { localMTTestLib1Ref });
            Assert.Equal("System.Object[missing]", ((SourceModuleSymbol)c2.Assembly.Modules[0]).GetCorLibType(SpecialType.System_Object).ToTestDisplayString());
        }
 
        [Fact]
        public void CrossModuleReferences1()
        {
            var compilationDef1 = @"
class Test1 : M3
{
}
 
class Test2 : M4
{
}
";
            var crossRefModule1 = TestReferences.SymbolsTests.netModule.CrossRefModule1;
            var crossRefModule2 = TestReferences.SymbolsTests.netModule.CrossRefModule2;
            var crossRefLib = TestReferences.SymbolsTests.netModule.CrossRefLib;
 
            var compilation1 = CreateCompilation(compilationDef1, new MetadataReference[] { crossRefLib }, TestOptions.ReleaseDll);
 
            compilation1.VerifyDiagnostics();
 
            var test1 = compilation1.GetTypeByMetadataName("Test1");
            var test2 = compilation1.GetTypeByMetadataName("Test2");
 
            Assert.False(test1.BaseType().IsErrorType());
            Assert.False(test1.BaseType().BaseType().IsErrorType());
            Assert.False(test2.BaseType().IsErrorType());
            Assert.False(test2.BaseType().BaseType().IsErrorType());
            Assert.False(test2.BaseType().BaseType().BaseType().IsErrorType());
 
            var compilationDef2 = @"
public class M3 : M1
{}
 
public class M4 : M2
{}
";
            var compilation2 = CreateCompilation(compilationDef2, new MetadataReference[] { crossRefModule1, crossRefModule2 }, TestOptions.ReleaseDll);
 
            compilation2.VerifyDiagnostics();
 
            var m3 = compilation2.GetTypeByMetadataName("M3");
            var m4 = compilation2.GetTypeByMetadataName("M4");
 
            Assert.False(m3.BaseType().IsErrorType());
            Assert.False(m3.BaseType().BaseType().IsErrorType());
            Assert.False(m4.BaseType().IsErrorType());
            Assert.False(m4.BaseType().BaseType().IsErrorType());
 
            var compilation3 = CreateCompilation(compilationDef2, new MetadataReference[] { crossRefModule2 }, TestOptions.ReleaseDll);
 
            m3 = compilation3.GetTypeByMetadataName("M3");
            m4 = compilation3.GetTypeByMetadataName("M4");
 
            Assert.True(m3.BaseType().IsErrorType());
            Assert.False(m4.BaseType().IsErrorType());
            Assert.True(m4.BaseType().BaseType().IsErrorType());
 
            // Expected:
            //error CS0246: The type or namespace name 'M1' could not be found (are you missing a using directive or an
            //        assembly reference?)
            //CrossRefModule2.netmodule: error CS0011: The base class or interface 'M1' in assembly 'CrossRefModule1.netmodule'
            //        referenced by type 'M2' could not be resolved
 
            DiagnosticDescription[] errors = {
                // (2,19): error CS0246: The type or namespace name 'M1' could not be found (are you missing a using directive or an assembly reference?)
                // public class M3 : M1
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "M1").WithArguments("M1"),
                // (5,19): error CS7079: The type 'M1' is defined in a module that has not been added. You must add the module 'CrossRefModule1.netmodule'.
                // public class M4 : M2
                Diagnostic(ErrorCode.ERR_NoTypeDefFromModule, "M2").WithArguments("M1", "CrossRefModule1.netmodule"),
                // error CS8014: Reference to 'CrossRefModule1.netmodule' netmodule missing.
                Diagnostic(ErrorCode.ERR_MissingNetModuleReference).WithArguments("CrossRefModule1.netmodule")
                                             };
 
            compilation3.VerifyDiagnostics(errors);
        }
    }
}