/// <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(_nestedTypeNameSeparators); if (parts.Length > 0) { mdName = MetadataTypeName.FromFullName(parts[0], useCLSCompliantNameArityEncoding); 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 = (!isWellKnownType || IsValidWellKnownType(temp)) ? temp : null; } } } else { mdName = MetadataTypeName.FromFullName(metadataName, useCLSCompliantNameArityEncoding); type = GetTopLevelTypeByMetadataName(ref mdName, assemblyOpt: null, includeReferences: includeReferences, isWellKnownType: isWellKnownType, warnings: warnings); } return(((object)type == null || type.IsErrorType()) ? null : type); }
internal override Symbol GetDeclaredSpecialTypeMember(SpecialMember member) { #if DEBUG foreach (var module in this.Modules) { Debug.Assert(module.GetReferencedAssemblies().Length == 0); } #endif 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 = CSharpCompilation.GetRuntimeMember( type, descriptor, CSharpCompilation.SpecialMembersSignatureComparer.Instance, accessWithinOpt: null ); } Interlocked.CompareExchange( ref _lazySpecialTypeMembers[(int)member], result, ErrorTypeSymbol.UnknownResultType ); } return(_lazySpecialTypeMembers[(int)member]); }
/// <summary> /// Return true if the given type is valid as a calling convention modifier type. /// </summary> internal static bool IsCallingConventionModifier(NamedTypeSymbol modifierType) { Debug.Assert(modifierType.ContainingAssembly is not null || modifierType.IsErrorType()); return((object?)modifierType.ContainingAssembly == modifierType.ContainingAssembly?.CorLibrary && modifierType.Arity == 0 && modifierType.Name != "CallConv" && modifierType.Name.StartsWith("CallConv", StringComparison.Ordinal) && modifierType.IsCompilerServicesTopLevelType()); }
/// <summary> /// Checks if an applied attribute with the given attributeType matches the namespace name and type name of the given early attribute's description /// and the attribute description has a signature with parameter count equal to the given attribute syntax's argument list count. /// NOTE: We don't allow early decoded attributes to have optional parameters. /// </summary> internal static bool IsTargetEarlyAttribute(NamedTypeSymbol attributeType, AttributeSyntax attributeSyntax, AttributeDescription description) { Debug.Assert(!attributeType.IsErrorType()); int argumentCount = (attributeSyntax.ArgumentList != null) ? attributeSyntax.ArgumentList.Arguments.Count((arg) => arg.NameEquals == null) : 0; return(AttributeData.IsTargetEarlyAttribute(attributeType, argumentCount, description)); }
internal override void EarlyDecodeWellKnownAttributeType(NamedTypeSymbol attributeType, AttributeSyntax attributeSyntax) { Debug.Assert(!attributeType.IsErrorType()); // NOTE: OptionalAttribute is decoded specially before any of the other attributes and stored in the parameter // symbol (rather than in the EarlyWellKnownAttributeData) because it is needed during overload resolution. if (CSharpAttributeData.IsTargetEarlyAttribute(attributeType, attributeSyntax, AttributeDescription.OptionalAttribute)) { lazyHasOptionalAttribute = ThreeState.True; } }
private DiagnosticInfo DeriveUseSiteDiagnosticFromBase() { NamedTypeSymbol @base = this.BaseTypeNoUseSiteDiagnostics; while ((object)@base != null) { if (@base.IsErrorType() && @base is NoPiaIllegalGenericInstantiationSymbol) { return(@base.GetUseSiteDiagnostic()); } @base = @base.BaseTypeNoUseSiteDiagnostics; } return(null); }
protected SubstitutedNamedTypeSymbol(Symbol newContainer, TypeMap map, NamedTypeSymbol originalDefinition, NamedTypeSymbol constructedFrom = null, bool unbound = false) : base(originalDefinition) { Debug.Assert(originalDefinition.IsDefinition); Debug.Assert(!originalDefinition.IsErrorType()); _newContainer = newContainer; _inputMap = map; _unbound = unbound; // if we're substituting to create a new unconstructed type as a member of a constructed type, // then we must alpha rename the type parameters. if ((object)constructedFrom != null) { Debug.Assert(ReferenceEquals(constructedFrom.ConstructedFrom, constructedFrom)); _lazyTypeParameters = constructedFrom.TypeParameters; _lazyMap = map; } }
/// <summary> /// Resolves <see cref="System.Type"/> to a <see cref="TypeSymbol"/> available in this assembly /// its referenced assemblies. /// </summary> /// <param name="type">The type to resolve.</param> /// <param name="includeReferences">Use referenced assemblies for resolution.</param> /// <returns>The resolved symbol if successful or null on failure.</returns> internal TypeSymbol GetTypeByReflectionType(Type type, bool includeReferences) { System.Reflection.TypeInfo typeInfo = type.GetTypeInfo(); Debug.Assert(!typeInfo.IsByRef); // not supported rigth now (we don't accept open types as submission results nor host types): Debug.Assert(!typeInfo.ContainsGenericParameters); if (typeInfo.IsArray) { TypeSymbol symbol = GetTypeByReflectionType(typeInfo.GetElementType(), includeReferences); if ((object)symbol == null) { return(null); } int rank = typeInfo.GetArrayRank(); return(new ArrayTypeSymbol(this, symbol, ImmutableArray <CustomModifier> .Empty, rank)); } else if (typeInfo.IsPointer) { TypeSymbol symbol = GetTypeByReflectionType(typeInfo.GetElementType(), includeReferences); if ((object)symbol == null) { return(null); } return(new PointerTypeSymbol(symbol)); } else if (typeInfo.DeclaringType != null) { Debug.Assert(!typeInfo.IsArray); // consolidated generic arguments (includes arguments of all declaring types): Type[] genericArguments = typeInfo.GenericTypeArguments; int typeArgumentIndex = 0; var currentTypeInfo = typeInfo.IsGenericType ? typeInfo.GetGenericTypeDefinition().GetTypeInfo() : typeInfo; var nestedTypes = ArrayBuilder <System.Reflection.TypeInfo> .GetInstance(); while (true) { Debug.Assert(currentTypeInfo.IsGenericTypeDefinition || !currentTypeInfo.IsGenericType); nestedTypes.Add(currentTypeInfo); if (currentTypeInfo.DeclaringType == null) { break; } currentTypeInfo = currentTypeInfo.DeclaringType.GetTypeInfo(); } int i = nestedTypes.Count - 1; var symbol = (NamedTypeSymbol)GetTypeByReflectionType(nestedTypes[i].AsType(), includeReferences); if ((object)symbol == null) { return(null); } while (--i >= 0) { int forcedArity = nestedTypes[i].GenericTypeParameters.Length - nestedTypes[i + 1].GenericTypeParameters.Length; MetadataTypeName mdName = MetadataTypeName.FromTypeName(nestedTypes[i].Name, forcedArity: forcedArity); symbol = symbol.LookupMetadataType(ref mdName); if ((object)symbol == null || symbol.IsErrorType()) { return(null); } symbol = ApplyGenericArguments(symbol, genericArguments, ref typeArgumentIndex, includeReferences); if ((object)symbol == null) { return(null); } } nestedTypes.Free(); Debug.Assert(typeArgumentIndex == genericArguments.Length); return(symbol); } else { AssemblyIdentity assemblyId = AssemblyIdentity.FromAssemblyDefinition(typeInfo.Assembly); MetadataTypeName mdName = MetadataTypeName.FromNamespaceAndTypeName( typeInfo.Namespace ?? string.Empty, typeInfo.Name, forcedArity: typeInfo.GenericTypeArguments.Length); NamedTypeSymbol symbol = GetTopLevelTypeByMetadataName(ref mdName, assemblyId, includeReferences, isWellKnownType: false); if ((object)symbol == null || symbol.IsErrorType()) { return(null); } int typeArgumentIndex = 0; Type[] genericArguments = typeInfo.GenericTypeArguments; symbol = ApplyGenericArguments(symbol, genericArguments, ref typeArgumentIndex, includeReferences); Debug.Assert(typeArgumentIndex == genericArguments.Length); return(symbol); } }
protected virtual bool IsAttributeConditionallyOmitted(NamedTypeSymbol attributeType, SyntaxTree syntaxTree, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { // When early binding attributes, we don't want to determine if the attribute type is conditional and if so, must be emitted or not. // Invoking IsConditional property on attributeType can lead to a cycle, hence we delay this computation until after early binding. if (IsEarlyAttributeBinder) { return false; } Debug.Assert((object)attributeType != null); Debug.Assert(!attributeType.IsErrorType()); if (attributeType.IsConditional) { ImmutableArray<string> conditionalSymbols = attributeType.GetAppliedConditionalSymbols(); Debug.Assert(conditionalSymbols != null); if (syntaxTree.IsAnyPreprocessorSymbolDefined(conditionalSymbols)) { return false; } var baseType = attributeType.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics); if ((object)baseType != null && baseType.IsConditional) { return IsAttributeConditionallyOmitted(baseType, syntaxTree, ref useSiteDiagnostics); } return true; } else { return false; } }
private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol attributeType, DiagnosticBag diagnostics) { Debug.Assert(this.SkipSemanticModelBinder() == this.GetBinder(node).SkipSemanticModelBinder()); // If attribute name bound to an error type with a single named type // candidate symbol, we want to bind the attribute constructor // and arguments with that named type to generate better semantic info. // CONSIDER: Do we need separate code paths for IDE and // CONSIDER: batch compilation scenarios? Above mentioned scenario // CONSIDER: is not useful for batch compilation. NamedTypeSymbol attributeTypeForBinding = attributeType; LookupResultKind resultKind = LookupResultKind.Viable; if (attributeTypeForBinding.IsErrorType()) { var errorType = (ErrorTypeSymbol)attributeTypeForBinding; resultKind = errorType.ResultKind; if (errorType.CandidateSymbols.Length == 1 && errorType.CandidateSymbols[0] is NamedTypeSymbol) { attributeTypeForBinding = (NamedTypeSymbol)errorType.CandidateSymbols[0]; } } // Bind constructor and named attribute arguments using the attribute binder var argumentListOpt = node.ArgumentList; Binder attributeArgumentBinder = this.WithAdditionalFlags(BinderFlags.AttributeArgument); AnalyzedAttributeArguments analyzedArguments = attributeArgumentBinder.BindAttributeArguments(argumentListOpt, attributeTypeForBinding, diagnostics); HashSet<DiagnosticInfo> useSiteDiagnostics = null; // Bind attributeType's constructor based on the bound constructor arguments MethodSymbol attributeConstructor = attributeTypeForBinding.IsErrorType() ? null : BindAttributeConstructor(node, attributeTypeForBinding, analyzedArguments.ConstructorArguments, diagnostics, ref resultKind, suppressErrors: attributeType.IsErrorType(), useSiteDiagnostics: ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); if ((object)attributeConstructor != null) { ReportDiagnosticsIfObsolete(diagnostics, attributeConstructor, node, hasBaseReceiver: false); } var constructorArguments = analyzedArguments.ConstructorArguments; ImmutableArray<BoundExpression> boundConstructorArguments = constructorArguments.Arguments.ToImmutableAndFree(); ImmutableArray<string> boundConstructorArgumentNamesOpt = constructorArguments.GetNames(); ImmutableArray<BoundExpression> boundNamedArguments = analyzedArguments.NamedArguments; constructorArguments.Free(); return new BoundAttribute(node, attributeConstructor, boundConstructorArguments, boundConstructorArgumentNamesOpt, boundNamedArguments, resultKind, attributeType, hasErrors: resultKind != LookupResultKind.Viable); }
/// <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). 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 MissingMetadataTypeSymbol) { 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 MissingMetadataTypeSymbol)) { result = newResult; break; } } } bool foundMatchInThisAssembly = (i < count); Debug.Assert(!foundMatchInThisAssembly || (object)result.ContainingAssembly == (object)this); if (!foundMatchInThisAssembly && digThroughForwardedTypes) { // We didn't find the type System.Diagnostics.Debug.Assert(result is MissingMetadataTypeSymbol); NamedTypeSymbol forwarded = TryLookupForwardedMetadataTypeWithCycleDetection(ref emittedName, visitedAssemblies); if ((object)forwarded != null) { result = forwarded; } } System.Diagnostics.Debug.Assert((object)result != null); // Add result of the lookup into the cache if (digThroughForwardedTypes || foundMatchInThisAssembly) { CacheTopLevelMetadataType(ref emittedName, result); } return(result); } }
internal override void EarlyDecodeWellKnownAttributeType(NamedTypeSymbol attributeType, AttributeSyntax attributeSyntax) { Debug.Assert(!attributeType.IsErrorType()); // NOTE: OptionalAttribute is decoded specially before any of the other attributes and stored in the parameter // symbol (rather than in the EarlyWellKnownAttributeData) because it is needed during overload resolution. if (CSharpAttributeData.IsTargetEarlyAttribute(attributeType, attributeSyntax, AttributeDescription.OptionalAttribute)) { _lazyHasOptionalAttribute = ThreeState.True; } }