/// <summary> /// Lookup a type within the assembly using its canonical CLR metadata name. /// </summary> /// <param name="metadataName"></param> /// <param name="includeReferences"> /// If search within assembly fails, lookup in assemblies referenced by the primary module. /// For source assembly, this is equivalent to all assembly references given to compilation. /// </param> /// <param name="isWellKnownType"> /// Extra restrictions apply when searching for a well-known type. In particular, the type must be public. /// </param> /// <param name="useCLSCompliantNameArityEncoding"> /// While resolving the name, consider only types following CLS-compliant generic type names and arity encoding (ECMA-335, section 10.7.2). /// I.e. arity is inferred from the name and matching type must have the same emitted name and arity. /// </param> /// <param name="warnings"> /// A diagnostic bag to receive warnings if we should allow multiple definitions and pick one. /// </param> /// <returns>Null if the type can't be found.</returns> internal NamedTypeSymbol GetTypeByMetadataName( string metadataName, bool includeReferences, bool isWellKnownType, bool useCLSCompliantNameArityEncoding = false, DiagnosticBag warnings = null) { NamedTypeSymbol type = null; MetadataTypeName mdName; if (metadataName.IndexOf('+') >= 0) { var parts = metadataName.Split(s_nestedTypeNameSeparators); Debug.Assert(parts.Length > 0); mdName = MetadataTypeName.FromFullName(parts[0], useCLSCompliantNameArityEncoding); type = GetTypeByMetadataName(mdName.FullName, includeReferences, isWellKnownType); //type = GetTopLevelTypeByMetadataName(ref mdName, assemblyOpt: null, includeReferences: includeReferences, isWellKnownType: isWellKnownType, warnings: warnings); for (int i = 1; (object)type != null && !type.IsErrorType() && i < parts.Length; i++) { mdName = MetadataTypeName.FromTypeName(parts[i]); NamedTypeSymbol temp = type.LookupMetadataType(ref mdName); type = temp; //(!isWellKnownType || IsValidWellKnownType(temp)) ? temp : null; } //throw new NotImplementedException(); } else { mdName = MetadataTypeName.FromFullName(metadataName, useCLSCompliantNameArityEncoding); //type = GetTopLevelTypeByMetadataName(ref mdName, assemblyOpt: null, includeReferences: includeReferences, isWellKnownType: isWellKnownType, warnings: warnings); type = LookupTopLevelMetadataType(ref mdName, true); if (includeReferences && (type == null || type.IsErrorType())) { type = null; var assemblies = new HashSet <AssemblySymbol>() { this }; assemblies.UnionWith(this.DeclaringCompilation.GetBoundReferenceManager().GetReferencedAssemblies().Select(x => (AssemblySymbol)x.Value)); foreach (var ass in assemblies) { var t = ass.LookupTopLevelMetadataType(ref mdName, true); if (t != null && !t.IsErrorType()) { if ((object)type != null && type.ContainingAssembly != t.ContainingAssembly) { // TODO: ambiguity Debug.Assert(false, "ambiguity"); return(null); } type = (NamedTypeSymbol)t; } } } } return(((object)type == null || type.IsErrorType()) ? null : type); }
/// <summary> /// Lookup member declaration in predefined CorLib type in this Assembly. Only valid if this /// assembly is the Cor Library /// </summary> internal Symbol GetDeclaredSpecialTypeMember(SpecialMember member) { if (_lazySpecialTypeMembers == null || ReferenceEquals(_lazySpecialTypeMembers[(int)member], ErrorTypeSymbol.UnknownResultType)) { if (_lazySpecialTypeMembers == null) { var specialTypeMembers = new Symbol[(int)SpecialMember.Count]; for (int i = 0; i < specialTypeMembers.Length; i++) { specialTypeMembers[i] = ErrorTypeSymbol.UnknownResultType; } Interlocked.CompareExchange(ref _lazySpecialTypeMembers, specialTypeMembers, null); } var descriptor = SpecialMembers.GetDescriptor(member); NamedTypeSymbol type = GetDeclaredSpecialType((SpecialType)descriptor.DeclaringTypeId); Symbol result = null; if (!type.IsErrorType()) { result = PhpCompilation.GetRuntimeMember(type, ref descriptor, PhpCompilation.SpecialMembersSignatureComparer.Instance, null); } Interlocked.CompareExchange(ref _lazySpecialTypeMembers[(int)member], result, ErrorTypeSymbol.UnknownResultType); } return(_lazySpecialTypeMembers[(int)member]); }
private void CacheTopLevelMetadataType( ref MetadataTypeName emittedName, NamedTypeSymbol result) { NamedTypeSymbol result1 = null; result1 = _emittedNameToTypeMap.GetOrAdd(emittedName.ToKey(), result); Debug.Assert(result1 == result || (result.IsErrorType() && result1.IsErrorType())); // object identity may differ in error cases }
/// <summary> /// Lookup a top level type referenced from metadata, names should be /// compared case-sensitively. Detect cycles during lookup. /// </summary> /// <param name="emittedName"> /// Full type name, possibly with generic name mangling. /// </param> /// <param name="visitedAssemblies"> /// List of assemblies lookup has already visited (since type forwarding can introduce cycles). /// </param> /// <param name="digThroughForwardedTypes"> /// Take forwarded types into account. /// </param> internal sealed override NamedTypeSymbol LookupTopLevelMetadataTypeWithCycleDetection(ref MetadataTypeName emittedName, ConsList <AssemblySymbol> visitedAssemblies, bool digThroughForwardedTypes) { NamedTypeSymbol result = null; // This is a cache similar to the one used by MetaImport::GetTypeByName in native // compiler. The difference is that native compiler pre-populates the cache when it // loads types. Here we are populating the cache only with things we looked for, so that // next time we are looking for the same thing, the lookup is fast. This cache also // takes care of TypeForwarders. Gives about 8% win on subsequent lookups in some // scenarios. // // CONSIDER !!! // // However, it is questionable how often subsequent lookup by name is going to happen. // Currently it doesn't happen for TypeDef tokens at all, for TypeRef tokens, the // lookup by name is done once and the result is cached. So, multiple lookups by name // for the same type are going to happen only in these cases: // 1) Resolving GetType() in attribute application, type is encoded by name. // 2) TypeRef token isn't reused within the same module, i.e. multiple TypeRefs point to // the same type. // 3) Different Module refers to the same type, lookup once per Module (with exception of #2). // 4) Multitargeting - retargeting the type to a different version of assembly result = LookupTopLevelMetadataTypeInCache(ref emittedName); if ((object)result != null) { // We only cache result equivalent to digging through type forwarders, which // might produce an forwarder specific ErrorTypeSymbol. We don't want to // return that error symbol, unless digThroughForwardedTypes is true. if (digThroughForwardedTypes || (!result.IsErrorType() && (object)result.ContainingAssembly == (object)this)) { return(result); } // According to the cache, the type wasn't found, or isn't declared in this assembly (forwarded). throw new NotImplementedException(); //return new MissingMetadataTypeSymbol.TopLevel(this.Modules[0], ref emittedName); } else { // Now we will look for the type in each module of the assembly and pick the first type // we find, this is what native VB compiler does. var modules = this.Modules; var count = modules.Length; var i = 0; result = modules[i].LookupTopLevelMetadataType(ref emittedName); if (result is ErrorTypeSymbol) { for (i = 1; i < count; i++) { var newResult = modules[i].LookupTopLevelMetadataType(ref emittedName); // Hold on to the first missing type result, unless we found the type. if (!(newResult is ErrorTypeSymbol)) { result = newResult; break; } } } bool foundMatchInThisAssembly = (i < count); Debug.Assert(!foundMatchInThisAssembly || (object)result.ContainingAssembly == (object)this); if (!foundMatchInThisAssembly && digThroughForwardedTypes) { // We didn't find the type Debug.Assert(result is ErrorTypeSymbol); NamedTypeSymbol forwarded = TryLookupForwardedMetadataTypeWithCycleDetection(ref emittedName, visitedAssemblies); if ((object)forwarded != null) { result = forwarded; } } Debug.Assert((object)result != null); // Add result of the lookup into the cache if (digThroughForwardedTypes || foundMatchInThisAssembly) { CacheTopLevelMetadataType(ref emittedName, result); } return(result); } }