| File: Emitter\Model\MethodSymbolAdapter.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// 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; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal partial class #if DEBUG MethodSymbolAdapter : SymbolAdapter, #else MethodSymbol : #endif Cci.ITypeMemberReference, Cci.IMethodReference, Cci.IGenericMethodInstanceReference, Cci.ISpecializedMethodReference, Cci.ITypeDefinitionMember, Cci.IMethodDefinition { bool Cci.IDefinition.IsEncDeleted => false; Cci.IGenericMethodInstanceReference Cci.IMethodReference.AsGenericMethodInstanceReference { get { Debug.Assert(this.IsDefinitionOrDistinct()); if (!AdaptedMethodSymbol.IsDefinition && AdaptedMethodSymbol.IsGenericMethod) { return this; } return null; } } Cci.ISpecializedMethodReference Cci.IMethodReference.AsSpecializedMethodReference { get { Debug.Assert(this.IsDefinitionOrDistinct()); if (!AdaptedMethodSymbol.IsDefinition && (!AdaptedMethodSymbol.IsGenericMethod || PEModuleBuilder.IsGenericType(AdaptedMethodSymbol.ContainingType))) { Debug.Assert((object)AdaptedMethodSymbol.ContainingType != null && PEModuleBuilder.IsGenericType(AdaptedMethodSymbol.ContainingType)); return this; } return null; } } Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context) { return ResolvedMethodImpl(context); } Cci.ITypeReference Cci.ITypeMemberReference.GetContainingType(EmitContext context) { Debug.Assert(this.IsDefinitionOrDistinct()); var synthesizedGlobalMethod = AdaptedMethodSymbol.OriginalDefinition as SynthesizedGlobalMethodSymbol; if ((object)synthesizedGlobalMethod != null) { return synthesizedGlobalMethod.ContainingPrivateImplementationDetailsType; } NamedTypeSymbol containingType = AdaptedMethodSymbol.ContainingType; if (AdaptedMethodSymbol is SynthesizedExtensionMarker marker) { return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingMarkerType(marker); } else if (AdaptedMethodSymbol.IsExtensionBlockMember()) { return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingGroupingType((SourceNamedTypeSymbol)containingType); } var moduleBeingBuilt = (PEModuleBuilder)context.Module; return moduleBeingBuilt.Translate(containingType, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode, diagnostics: context.Diagnostics, needDeclaration: AdaptedMethodSymbol.IsDefinition); } void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor) { Debug.Assert(this.IsDefinitionOrDistinct()); if (!AdaptedMethodSymbol.IsDefinition) { if (AdaptedMethodSymbol.IsGenericMethod) { Debug.Assert(((Cci.IMethodReference)this).AsGenericMethodInstanceReference != null); visitor.Visit((Cci.IGenericMethodInstanceReference)this); } else { Debug.Assert(((Cci.IMethodReference)this).AsSpecializedMethodReference != null); visitor.Visit((Cci.ISpecializedMethodReference)this); } } else { PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)visitor.Context.Module; if (AdaptedMethodSymbol.ContainingModule == moduleBeingBuilt.SourceModule) { Debug.Assert(((Cci.IMethodReference)this).GetResolvedMethod(visitor.Context) != null); visitor.Visit((Cci.IMethodDefinition)this); } else { visitor.Visit((Cci.IMethodReference)this); } } } string Cci.INamedEntity.Name { get { return AdaptedMethodSymbol.MetadataName; } } bool Cci.IMethodReference.AcceptsExtraArguments { get { return AdaptedMethodSymbol.IsVararg; } } ushort Cci.IMethodReference.GenericParameterCount { get { return (ushort)AdaptedMethodSymbol.Arity; } } ushort Cci.ISignature.ParameterCount { get { return (ushort)AdaptedMethodSymbol.ParameterCount; } } Cci.IMethodDefinition Cci.IMethodReference.GetResolvedMethod(EmitContext context) { return ResolvedMethodImpl(context); } private Cci.IMethodDefinition ResolvedMethodImpl(EmitContext context) { Debug.Assert(this.IsDefinitionOrDistinct()); PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module; if (AdaptedMethodSymbol.IsDefinition && // can't be generic instantiation AdaptedMethodSymbol.ContainingModule == moduleBeingBuilt.SourceModule) // must be declared in the module we are building { Debug.Assert((object)AdaptedMethodSymbol.PartialDefinitionPart == null); // must be definition return this; } return null; } ImmutableArray<Cci.IParameterTypeInformation> Cci.IMethodReference.ExtraParameters { get { return ImmutableArray<Cci.IParameterTypeInformation>.Empty; } } Cci.CallingConvention Cci.ISignature.CallingConvention { get { return AdaptedMethodSymbol.CallingConvention; } } ImmutableArray<Cci.IParameterTypeInformation> Cci.ISignature.GetParameters(EmitContext context) { Debug.Assert(this.IsDefinitionOrDistinct()); PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module; if (AdaptedMethodSymbol.IsDefinition && AdaptedMethodSymbol.ContainingModule == moduleBeingBuilt.SourceModule) { return StaticCast<Cci.IParameterTypeInformation>.From(this.EnumerateDefinitionParameters()); } else { return moduleBeingBuilt.Translate(AdaptedMethodSymbol.Parameters); } } private ImmutableArray<Cci.IParameterDefinition> EnumerateDefinitionParameters() { Debug.Assert(AdaptedMethodSymbol.Parameters.All(p => p.IsDefinition)); #if DEBUG return AdaptedMethodSymbol.Parameters.SelectAsArray<ParameterSymbol, Cci.IParameterDefinition>(p => p.GetCciAdapter()); #else return StaticCast<Cci.IParameterDefinition>.From(AdaptedMethodSymbol.Parameters); #endif } ImmutableArray<Cci.ICustomModifier> Cci.ISignature.ReturnValueCustomModifiers { get { return ImmutableArray<Cci.ICustomModifier>.CastUp(AdaptedMethodSymbol.ReturnTypeWithAnnotations.CustomModifiers); } } ImmutableArray<Cci.ICustomModifier> Cci.ISignature.RefCustomModifiers { get { return ImmutableArray<Cci.ICustomModifier>.CastUp(AdaptedMethodSymbol.RefCustomModifiers); } } bool Cci.ISignature.ReturnValueIsByRef { get { return AdaptedMethodSymbol.RefKind.IsManagedReference(); } } Cci.ITypeReference Cci.ISignature.GetType(EmitContext context) { return ((PEModuleBuilder)context.Module).Translate(AdaptedMethodSymbol.ReturnType, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode, diagnostics: context.Diagnostics); } IEnumerable<Cci.ITypeReference> Cci.IGenericMethodInstanceReference.GetGenericArguments(EmitContext context) { PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module; Debug.Assert(((Cci.IMethodReference)this).AsGenericMethodInstanceReference != null); foreach (var arg in AdaptedMethodSymbol.TypeArgumentsWithAnnotations) { Debug.Assert(arg.CustomModifiers.IsEmpty); yield return moduleBeingBuilt.Translate(arg.Type, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode, diagnostics: context.Diagnostics); } } Cci.IMethodReference Cci.IGenericMethodInstanceReference.GetGenericMethod(EmitContext context) { Debug.Assert(((Cci.IMethodReference)this).AsGenericMethodInstanceReference != null); NamedTypeSymbol container = AdaptedMethodSymbol.ContainingType; if (!PEModuleBuilder.IsGenericType(container)) { // NoPia method might come through here. return ((PEModuleBuilder)context.Module).Translate( (MethodSymbol)AdaptedMethodSymbol.OriginalDefinition, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode, diagnostics: context.Diagnostics, needDeclaration: true); } MethodSymbol methodSymbol = AdaptedMethodSymbol.ConstructedFrom; return new SpecializedMethodReference(methodSymbol); } Cci.IMethodReference Cci.ISpecializedMethodReference.UnspecializedVersion { get { Debug.Assert(((Cci.IMethodReference)this).AsSpecializedMethodReference != null); return ((MethodSymbol)AdaptedMethodSymbol.OriginalDefinition).GetCciAdapter(); } } #nullable enable Cci.ITypeDefinition Cci.ITypeDefinitionMember.ContainingTypeDefinition { get { CheckDefinitionInvariant(); if (AdaptedMethodSymbol.OriginalDefinition is SynthesizedGlobalMethodSymbol synthesizedGlobalMethod) { return synthesizedGlobalMethod.ContainingPrivateImplementationDetailsType; } if (AdaptedMethodSymbol is SynthesizedExtensionMarker marker) { return ((SourceMemberContainerTypeSymbol)AdaptedMethodSymbol.ContainingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingMarkerType(marker); } else if (AdaptedMethodSymbol.IsExtensionBlockMember()) { var containingType = AdaptedMethodSymbol.ContainingType; return ((SourceMemberContainerTypeSymbol)containingType.ContainingType).GetExtensionGroupingInfo().GetCorrespondingGroupingType((SourceNamedTypeSymbol)containingType); } return AdaptedMethodSymbol.ContainingType.GetCciAdapter(); } } Cci.TypeMemberVisibility Cci.ITypeDefinitionMember.Visibility { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.MetadataVisibility; } } bool Cci.IMethodDefinition.HasBody { get { CheckDefinitionInvariant(); return Cci.DefaultImplementations.HasBody(this); } } Cci.IMethodBody? Cci.IMethodDefinition.GetBody(EmitContext context) { CheckDefinitionInvariant(); return ((PEModuleBuilder)context.Module).GetMethodBody(AdaptedMethodSymbol); } IEnumerable<Cci.IGenericMethodParameter> Cci.IMethodDefinition.GenericParameters { get { CheckDefinitionInvariant(); foreach (var @param in AdaptedMethodSymbol.TypeParameters) { Debug.Assert(@param.IsDefinition); yield return @param.GetCciAdapter(); } } } bool Cci.IMethodDefinition.HasDeclarativeSecurity { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.HasDeclarativeSecurity; } } IEnumerable<Cci.SecurityAttribute> Cci.IMethodDefinition.SecurityAttributes { get { CheckDefinitionInvariant(); Debug.Assert(AdaptedMethodSymbol.HasDeclarativeSecurity); return AdaptedMethodSymbol.GetSecurityInformation(); } } bool Cci.IMethodDefinition.IsAbstract { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.IsAbstract; } } bool Cci.IMethodDefinition.IsAccessCheckedOnOverride { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.IsAccessCheckedOnOverride; } } bool Cci.IMethodDefinition.IsConstructor { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.MethodKind == MethodKind.Constructor; } } bool Cci.IMethodDefinition.IsExternal { get { CheckDefinitionInvariant(); return !AdaptedMethodSymbol.ContainingType.IsExtension && AdaptedMethodSymbol.IsExternal; } } bool Cci.IMethodDefinition.IsHiddenBySignature { get { CheckDefinitionInvariant(); return !AdaptedMethodSymbol.HidesBaseMethodsByName; } } bool Cci.IMethodDefinition.IsNewSlot { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.IsMetadataNewSlot(AdaptedSymbol.ContainingModule); // Use in context of other module is not expected. See 'CheckDefinitionInvariant' above. } } bool Cci.IMethodDefinition.IsPlatformInvoke { get { CheckDefinitionInvariant(); return !AdaptedMethodSymbol.ContainingType.IsExtension && AdaptedMethodSymbol.GetDllImportData() != null; } } #nullable disable Cci.IPlatformInvokeInformation Cci.IMethodDefinition.PlatformInvokeData { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.ContainingType.IsExtension ? null : AdaptedMethodSymbol.GetDllImportData(); } } System.Reflection.MethodImplAttributes Cci.IMethodDefinition.GetImplementationAttributes(EmitContext context) { CheckDefinitionInvariant(); return AdaptedMethodSymbol.ContainingType.IsExtension ? default : AdaptedMethodSymbol.ImplementationAttributes; } bool Cci.IMethodDefinition.IsRuntimeSpecial { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.HasRuntimeSpecialName; } } bool Cci.IMethodDefinition.IsSealed { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.IsMetadataFinal; } } bool Cci.IMethodDefinition.IsSpecialName { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.HasSpecialName; } } bool Cci.IMethodDefinition.IsStatic { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.IsStatic; } } bool Cci.IMethodDefinition.IsVirtual { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.IsMetadataVirtual(AdaptedSymbol.ContainingModule); // Use in context of other module is not expected. See 'CheckDefinitionInvariant' above. } } ImmutableArray<Cci.IParameterDefinition> Cci.IMethodDefinition.Parameters { get { CheckDefinitionInvariant(); return EnumerateDefinitionParameters(); } } bool Cci.IMethodDefinition.RequiresSecurityObject { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.RequiresSecurityObject; } } IEnumerable<Cci.ICustomAttribute> Cci.IMethodDefinition.GetReturnValueAttributes(EmitContext context) { CheckDefinitionInvariant(); ImmutableArray<CSharpAttributeData> userDefined = AdaptedMethodSymbol.GetReturnTypeAttributes(); ArrayBuilder<CSharpAttributeData> synthesized = null; AdaptedMethodSymbol.AddSynthesizedReturnTypeAttributes((PEModuleBuilder)context.Module, ref synthesized); // Note that callers of this method (CCI and ReflectionEmitter) have to enumerate // all items of the returned iterator, otherwise the synthesized ArrayBuilder may leak. return AdaptedMethodSymbol.GetCustomAttributesToEmit(userDefined, synthesized, isReturnType: true, emittingAssemblyAttributesInNetModule: false); } bool Cci.IMethodDefinition.ReturnValueIsMarshalledExplicitly { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.ReturnValueIsMarshalledExplicitly; } } Cci.IMarshallingInformation Cci.IMethodDefinition.ReturnValueMarshallingInformation { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.ReturnValueMarshallingInformation; } } ImmutableArray<byte> Cci.IMethodDefinition.ReturnValueMarshallingDescriptor { get { CheckDefinitionInvariant(); return AdaptedMethodSymbol.ReturnValueMarshallingDescriptor; } } Cci.INamespace Cci.IMethodDefinition.ContainingNamespace { get { return AdaptedMethodSymbol.ContainingNamespace.GetCciAdapter(); } } } internal partial class MethodSymbol { #if DEBUG private MethodSymbolAdapter _lazyAdapter; protected sealed override SymbolAdapter GetCciAdapterImpl() => GetCciAdapter(); internal new MethodSymbolAdapter GetCciAdapter() { if (_lazyAdapter is null) { return InterlockedOperations.Initialize(ref _lazyAdapter, CreateCciAdapter()); } return _lazyAdapter; } protected virtual MethodSymbolAdapter CreateCciAdapter() { return new MethodSymbolAdapter(this); } #else internal MethodSymbol AdaptedMethodSymbol => this; internal new MethodSymbol GetCciAdapter() { return this; } #endif internal virtual bool IsAccessCheckedOnOverride { get { CheckDefinitionInvariant(); // Enforce C#'s notion of internal virtual // If the method is private or internal and virtual but not final // Set the new bit to indicate that it can only be overridden // by classes that can normally access this member. Accessibility accessibility = this.DeclaredAccessibility; return (accessibility == Accessibility.Private || accessibility == Accessibility.ProtectedAndInternal || accessibility == Accessibility.Internal) && this.IsMetadataVirtual(ContainingModule) && !this.IsMetadataFinal; // Use in context of other module is not expected. See 'CheckDefinitionInvariant' above. } } internal virtual bool IsExternal { get { CheckDefinitionInvariant(); // Delegate methods are implemented by the runtime. // Note that we don't force methods marked with MethodImplAttributes.InternalCall or MethodImplAttributes.Runtime // to be external, so it is possible to mark methods with bodies by these flags. It's up to the VM to interpret these flags // and throw runtime exception if they are applied incorrectly. return this.IsExtern || (object)ContainingType != null && ContainingType.TypeKind == TypeKind.Delegate; } } /// <summary> /// This method indicates whether or not the runtime will regard the method /// as newslot (as indicated by the presence of the "newslot" modifier in the /// signature). /// WARN WARN WARN: We won't have a final value for this until declaration /// diagnostics have been computed for all <see cref="SourceMemberContainerTypeSymbol"/>s, so pass /// ignoringInterfaceImplementationChanges: true if you need a value sooner /// and aren't concerned about tweaks made to satisfy interface implementation /// requirements. /// NOTE: Not ignoring changes can only result in a value that is more true. /// </summary> /// <param name="context">See <see cref="IsMetadataVirtual(ModuleSymbol?, bool)"/></param> /// <param name="ignoreInterfaceImplementationChanges">See summary.</param> #nullable enable internal abstract bool IsMetadataNewSlot(ModuleSymbol? context, bool ignoreInterfaceImplementationChanges = false); #nullable disable internal virtual bool HasRuntimeSpecialName { get { CheckDefinitionInvariant(); return this.MethodKind == MethodKind.Constructor || this.MethodKind == MethodKind.StaticConstructor; } } internal virtual bool IsMetadataFinal { get { // destructors should override this behavior Debug.Assert(this.MethodKind != MethodKind.Destructor); return this.IsSealed || (this.IsMetadataVirtual(this.ContainingModule) && !(this.IsVirtual || this.IsOverride || this.IsAbstract || this.MethodKind == MethodKind.Destructor)); } } /// <summary> /// This method indicates whether or not the runtime will regard the method /// as virtual (as indicated by the presence of the "virtual" modifier in the /// signature). /// WARN WARN WARN: /// When called in <paramref name="context"/> of the declaring module we won't have a final value for this until declaration /// diagnostics have been computed for all <see cref="SourceMemberContainerTypeSymbol"/>s, so pass /// 'true' for <paramref name="ignoreInterfaceImplementationChanges"/> if you need a value sooner /// and aren't concerned about tweaks made to satisfy interface implementation /// requirements. /// NOTE: Not ignoring changes can only result in a value that is more true. /// </summary> /// <param name="context"> /// Module "asking" the question. For example, when "asking" the question during emit, /// the module that is being emitted. Etc. /// This is needed to determine whether we should force compute the final value. /// Fine to pass null if <paramref name="ignoreInterfaceImplementationChanges"/> is 'true'. /// </param> /// <param name="ignoreInterfaceImplementationChanges">See summary.</param> #nullable enable internal abstract bool IsMetadataVirtual(ModuleSymbol? context, bool ignoreInterfaceImplementationChanges = false); #nullable disable internal virtual bool ReturnValueIsMarshalledExplicitly { get { CheckDefinitionInvariant(); return this.ReturnValueMarshallingInformation != null; } } internal virtual ImmutableArray<byte> ReturnValueMarshallingDescriptor { get { CheckDefinitionInvariant(); return default(ImmutableArray<byte>); } } } #if DEBUG internal partial class MethodSymbolAdapter { internal MethodSymbolAdapter(MethodSymbol underlyingMethodSymbol) { AdaptedMethodSymbol = underlyingMethodSymbol; if (underlyingMethodSymbol is NativeIntegerMethodSymbol) { // Emit should use underlying symbol only. throw ExceptionUtilities.Unreachable(); } } internal sealed override Symbol AdaptedSymbol => AdaptedMethodSymbol; internal MethodSymbol AdaptedMethodSymbol { get; } } #endif }