/// <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); }
internal override bool GetGuidString(out string guidString) { return(_underlyingType.GetGuidString(out guidString)); }