public void NoPIALocalTypesEquivalentToEachOtherStructAsMethodParameterType()
        {
            //Structure - As method parameter type in external assembly (test this by passing the parameter with a variable which was declared in the current assembly)


            var localTypeSource = @"static class TypeSubstitution
{
    FooStruct myOwnVar = null;
    public static void Main()
    {
        myOwnVar = new FooStruct();
        myOwnVar.Structure = -1;
        ExternalAsm1.Scen1(myOwnVar);
    }
}
";

            var localConsumer = CreateEmptyCompilation(assemblyName: "Dummy", source: new string[] { localTypeSource },
                                                       references: new MetadataReference[] {
                TestReferences.SymbolsTests.NoPia.GeneralPia,
                TestReferences.SymbolsTests.NoPia.ExternalAsm1,
            });

            var localConsumerRefsAsm = localConsumer.Assembly.GetNoPiaResolutionAssemblies();

            Assert.Equal(3, localConsumerRefsAsm.First(arg => arg.Name == "GeneralPia").Modules.FirstOrDefault().GetReferencedAssemblies().Length);
            Assert.Equal(3, localConsumerRefsAsm.First(arg => arg.Name == "GeneralPia").Modules.FirstOrDefault().GetReferencedAssemblySymbols().Length);

            var canonicalType = localConsumerRefsAsm.First(arg => arg.Name == "GeneralPia").GlobalNamespace.GetTypeMembers("FooStruct").Single();

            NamedTypeSymbol classLocalType   = localConsumer.GlobalNamespace.GetTypeMembers("TypeSubstitution").Single();
            FieldSymbol     localFieldSymbol = classLocalType.GetMembers("myOwnVar").OfType <FieldSymbol>().Single();

            NamedTypeSymbol classRefLocalType        = localConsumerRefsAsm.First(arg => arg.Name == "ExternalAsm1").GlobalNamespace.GetTypeMembers("ExternalAsm1").Single();
            MethodSymbol    refMethodSymbol          = classRefLocalType.GetMembers("Scen1").OfType <MethodSymbol>().Single();
            ImmutableArray <ParameterSymbol> param   = refMethodSymbol.Parameters;
            NoPiaMissingCanonicalTypeSymbol  missing = (NoPiaMissingCanonicalTypeSymbol)param.First().Type;

            Assert.Same(localConsumerRefsAsm.First(arg => arg.Name == "ExternalAsm1"), missing.EmbeddingAssembly);
            Assert.Null(missing.Guid);
            Assert.Equal(canonicalType.ToTestDisplayString(), missing.FullTypeName);
            Assert.Equal("f9c2d51d-4f44-45f0-9eda-c9d599b58257", missing.Scope);
            Assert.Equal(canonicalType.ToTestDisplayString(), missing.Identifier);
            Assert.Same(canonicalType, localFieldSymbol.Type);
            Assert.IsType <NoPiaMissingCanonicalTypeSymbol>(param[0].Type);
        }
        public void NoPIALocalTypesEquivalentToEachOtherEnumAsReturnTypeInExternalAssembly()
        {
            //Enum - As return type in external assembly


            var localTypeSource = @"static class TypeSubstitution
{
    FooEnum myLocalType = 0;
    public static void Main()
    {
       FooEnum myLocalType = 0;
       myLocalType = ExternalAsm1.Scen3(5);
    }
}";

            var localConsumer = CreateEmptyCompilation(assemblyName: "Dummy", source: new string[] { localTypeSource },
                                                       references: new List <MetadataReference>()
            {
                TestReferences.SymbolsTests.NoPia.GeneralPia,
                TestReferences.SymbolsTests.NoPia.ExternalAsm1
            });

            var localConsumerRefsAsm = localConsumer.Assembly.GetNoPiaResolutionAssemblies();
            var canonicalType        = localConsumerRefsAsm.First(arg => arg.Name == "GeneralPia").GlobalNamespace.GetTypeMembers("FooEnum").Single();

            NamedTypeSymbol classLocalType   = localConsumer.GlobalNamespace.GetTypeMembers("TypeSubstitution").Single();
            FieldSymbol     localFieldSymbol = classLocalType.GetMembers("myLocalType").OfType <FieldSymbol>().Single();

            NamedTypeSymbol classRefLocalType       = localConsumerRefsAsm.First(arg => arg.Name == "ExternalAsm1").GlobalNamespace.GetTypeMembers("ExternalAsm1").Single();
            MethodSymbol    methodSymbol            = classRefLocalType.GetMembers("Scen3").OfType <MethodSymbol>().Single();
            NoPiaMissingCanonicalTypeSymbol missing = (NoPiaMissingCanonicalTypeSymbol)methodSymbol.ReturnType;

            Assert.Same(localConsumerRefsAsm.First(arg => arg.Name == "ExternalAsm1"), missing.EmbeddingAssembly);
            Assert.Null(missing.Guid);
            Assert.Equal(canonicalType.ToTestDisplayString(), missing.FullTypeName);
            Assert.Equal("f9c2d51d-4f44-45f0-9eda-c9d599b58257", missing.Scope);
            Assert.Equal(canonicalType.ToTestDisplayString(), missing.Identifier);
            Assert.Same(canonicalType, localFieldSymbol.Type);
            Assert.IsType <NoPiaMissingCanonicalTypeSymbol>(methodSymbol.ReturnType);
        }
Beispiel #3
0
        /// <summary>
        /// Find canonical type for NoPia embedded type.
        /// </summary>
        /// <returns>
        /// Symbol for the canonical type or an ErrorTypeSymbol. Never returns null.
        /// </returns>
        internal static NamedTypeSymbol SubstituteNoPiaLocalType(
            ref MetadataTypeName name,
            bool isInterface,
            TypeSymbol baseType,
            string interfaceGuid,
            string scope,
            string identifier,
            AssemblySymbol referringAssembly)
        {
            NamedTypeSymbol result = null;

            Guid interfaceGuidValue     = new Guid();
            bool haveInterfaceGuidValue = false;
            Guid scopeGuidValue         = new Guid();
            bool haveScopeGuidValue     = false;

            if (isInterface && interfaceGuid != null)
            {
                haveInterfaceGuidValue = Guid.TryParse(interfaceGuid, out interfaceGuidValue);

                if (haveInterfaceGuidValue)
                {
                    // To have consistent errors.
                    scope      = null;
                    identifier = null;
                }
            }

            if (scope != null)
            {
                haveScopeGuidValue = Guid.TryParse(scope, out scopeGuidValue);
            }

            foreach (AssemblySymbol assembly in referringAssembly.GetNoPiaResolutionAssemblies())
            {
                Debug.Assert((object)assembly != null);
                if (ReferenceEquals(assembly, referringAssembly))
                {
                    continue;
                }

                NamedTypeSymbol candidate = assembly.LookupTopLevelMetadataType(ref name, digThroughForwardedTypes: false);
                Debug.Assert(!candidate.IsGenericType);

                // Ignore type forwarders, error symbols and non-public types
                if (candidate.Kind == SymbolKind.ErrorType ||
                    !ReferenceEquals(candidate.ContainingAssembly, assembly) ||
                    candidate.DeclaredAccessibility != Accessibility.Public)
                {
                    continue;
                }

                // Ignore NoPia local types.
                // If candidate is coming from metadata, we don't need to do any special check,
                // because we do not create symbols for local types. However, local types defined in source
                // is another story. However, if compilation explicitly defines a local type, it should be
                // represented by a retargeting assembly, which is supposed to hide the local type.
                Debug.Assert(!(assembly is SourceAssemblySymbol) || !((SourceAssemblySymbol)assembly).SourceModule.MightContainNoPiaLocalTypes());

                string candidateGuid;
                bool   haveCandidateGuidValue = false;
                Guid   candidateGuidValue     = new Guid();

                // The type must be of the same kind (interface, struct, delegate or enum).
                switch (candidate.TypeKind)
                {
                case TypeKind.Interface:
                    if (!isInterface)
                    {
                        continue;
                    }

                    // Get candidate's Guid
                    if (candidate.GetGuidString(out candidateGuid) && candidateGuid != null)
                    {
                        haveCandidateGuidValue = Guid.TryParse(candidateGuid, out candidateGuidValue);
                    }

                    break;

                case TypeKind.Delegate:
                case TypeKind.Enum:
                case TypeKind.Struct:

                    if (isInterface)
                    {
                        continue;
                    }

                    // Let's use a trick. To make sure the kind is the same, make sure
                    // base type is the same.
                    if (!ReferenceEquals(baseType, candidate.BaseTypeNoUseSiteDiagnostics))
                    {
                        continue;
                    }

                    break;

                default:
                    continue;
                }

                if (haveInterfaceGuidValue || haveCandidateGuidValue)
                {
                    if (!haveInterfaceGuidValue || !haveCandidateGuidValue ||
                        candidateGuidValue != interfaceGuidValue)
                    {
                        continue;
                    }
                }
                else
                {
                    if (!haveScopeGuidValue || identifier == null || !identifier.Equals(name.FullName))
                    {
                        continue;
                    }

                    // Scope guid must match candidate's assembly guid.
                    haveCandidateGuidValue = false;
                    if (assembly.GetGuidString(out candidateGuid) && candidateGuid != null)
                    {
                        haveCandidateGuidValue = Guid.TryParse(candidateGuid, out candidateGuidValue);
                    }

                    if (!haveCandidateGuidValue || scopeGuidValue != candidateGuidValue)
                    {
                        continue;
                    }
                }

                // OK. It looks like we found canonical type definition.
                if ((object)result != null)
                {
                    // Ambiguity
                    result = new NoPiaAmbiguousCanonicalTypeSymbol(referringAssembly, result, candidate);
                    break;
                }

                result = candidate;
            }

            if ((object)result == null)
            {
                result = new NoPiaMissingCanonicalTypeSymbol(
                    referringAssembly,
                    name.FullName,
                    interfaceGuid,
                    scope,
                    identifier);
            }

            return(result);
        }