| File: Symbols\Retargeting\RetargetingNamedTypeSymbol.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.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.Cci; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting { /// <summary> /// Represents a type of a RetargetingModuleSymbol. Essentially this is a wrapper around /// another NamedTypeSymbol that is responsible for retargeting referenced symbols from one assembly to another. /// It can retarget symbols for multiple assemblies at the same time. /// </summary> internal sealed class RetargetingNamedTypeSymbol : WrappedNamedTypeSymbol { /// <summary> /// Owning RetargetingModuleSymbol. /// </summary> private readonly RetargetingModuleSymbol _retargetingModule; private ImmutableArray<TypeParameterSymbol> _lazyTypeParameters; private NamedTypeSymbol _lazyBaseType = ErrorTypeSymbol.UnknownResultType; private ImmutableArray<NamedTypeSymbol> _lazyInterfaces = default(ImmutableArray<NamedTypeSymbol>); private NamedTypeSymbol _lazyDeclaredBaseType = ErrorTypeSymbol.UnknownResultType; private ImmutableArray<NamedTypeSymbol> _lazyDeclaredInterfaces; private ImmutableArray<CSharpAttributeData> _lazyCustomAttributes; private CachedUseSiteInfo<AssemblySymbol> _lazyCachedUseSiteInfo = CachedUseSiteInfo<AssemblySymbol>.Uninitialized; private StrongBox<ParameterSymbol> _lazyExtensionParameter; private ImmutableArray<(Cci.INestedTypeReference GroupingType, ImmutableArray<Cci.INestedTypeReference> MarkerTypes)> _lazyExtensionGroupingAndMarkerTypesForTypeForwarding; public RetargetingNamedTypeSymbol(RetargetingModuleSymbol retargetingModule, NamedTypeSymbol underlyingType, TupleExtraData tupleData = null) : base(underlyingType, tupleData) { Debug.Assert((object)retargetingModule != null); Debug.Assert(!(underlyingType is RetargetingNamedTypeSymbol)); _retargetingModule = retargetingModule; } protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) { return new RetargetingNamedTypeSymbol(_retargetingModule, _underlyingType, newData); } private RetargetingModuleSymbol.RetargetingSymbolTranslator RetargetingTranslator { get { return _retargetingModule.RetargetingTranslator; } } public override ImmutableArray<TypeParameterSymbol> TypeParameters { get { if (_lazyTypeParameters.IsDefault) { if (this.Arity == 0) { _lazyTypeParameters = ImmutableArray<TypeParameterSymbol>.Empty; } else { ImmutableInterlocked.InterlockedCompareExchange(ref _lazyTypeParameters, this.RetargetingTranslator.Retarget(_underlyingType.TypeParameters), default(ImmutableArray<TypeParameterSymbol>)); } } return _lazyTypeParameters; } } internal override ImmutableArray<TypeWithAnnotations> TypeArgumentsWithAnnotationsNoUseSiteDiagnostics { get { // This is always the instance type, so the type arguments are the same as the type parameters. return GetTypeParametersAsTypeArguments(); } } internal sealed override ParameterSymbol ExtensionParameter { get { if (_lazyExtensionParameter is null) { var extensionParameter = _underlyingType.ExtensionParameter is { } receiverParameter ? new RetargetingExtensionReceiverParameterSymbol(this, receiverParameter) : null; Interlocked.CompareExchange(ref _lazyExtensionParameter, new StrongBox<ParameterSymbol>(extensionParameter), null); } return _lazyExtensionParameter.Value; } } public override MethodSymbol TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) { Debug.Assert(this.IsExtension); Debug.Assert(method.IsDefinition); Debug.Assert(method.ContainingType == (object)this); var underlyingImplementation = _underlyingType.TryGetCorrespondingExtensionImplementationMethod(((RetargetingMethodSymbol)method).UnderlyingMethod); if (underlyingImplementation is null) { return null; } return RetargetingTranslator.Retarget(underlyingImplementation); } public override NamedTypeSymbol ConstructedFrom { get { return this; } } public override NamedTypeSymbol EnumUnderlyingType { get { var underlying = _underlyingType.EnumUnderlyingType; return (object)underlying == null ? null : this.RetargetingTranslator.Retarget(underlying, RetargetOptions.RetargetPrimitiveTypesByTypeCode); // comes from field's signature. } } public override IEnumerable<string> MemberNames { get { return _underlyingType.MemberNames; } } internal override bool HasDeclaredRequiredMembers => _underlyingType.HasDeclaredRequiredMembers; internal override bool IsClosed => _underlyingType.IsClosed; internal override ImmutableArray<NamedTypeSymbol> CandidateClosedSubtypeDefinitions => this.RetargetingTranslator.Retarget(_underlyingType.CandidateClosedSubtypeDefinitions); public override ImmutableArray<Symbol> GetMembers() { return this.RetargetingTranslator.Retarget(_underlyingType.GetMembers()); } internal override ImmutableArray<Symbol> GetMembersUnordered() { return this.RetargetingTranslator.Retarget(_underlyingType.GetMembersUnordered()); } public override ImmutableArray<Symbol> GetMembers(string name) { return this.RetargetingTranslator.Retarget(_underlyingType.GetMembers(name)); } internal override IEnumerable<FieldSymbol> GetFieldsToEmit() { foreach (FieldSymbol f in _underlyingType.GetFieldsToEmit()) { yield return this.RetargetingTranslator.Retarget(f); } } internal override IEnumerable<MethodSymbol> GetMethodsToEmit() { bool isInterface = _underlyingType.IsInterfaceType(); foreach (MethodSymbol method in _underlyingType.GetMethodsToEmit()) { Debug.Assert((object)method != null); int gapSize = isInterface ? Microsoft.CodeAnalysis.ModuleExtensions.GetVTableGapSize(method.MetadataName) : 0; if (gapSize > 0) { do { yield return null; gapSize--; } while (gapSize > 0); } else { yield return this.RetargetingTranslator.Retarget(method); } } } internal override IEnumerable<PropertySymbol> GetPropertiesToEmit() { foreach (PropertySymbol p in _underlyingType.GetPropertiesToEmit()) { yield return this.RetargetingTranslator.Retarget(p); } } internal override IEnumerable<EventSymbol> GetEventsToEmit() { foreach (EventSymbol e in _underlyingType.GetEventsToEmit()) { yield return this.RetargetingTranslator.Retarget(e); } } internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers() { return this.RetargetingTranslator.Retarget(_underlyingType.GetEarlyAttributeDecodingMembers()); } internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers(string name) { return this.RetargetingTranslator.Retarget(_underlyingType.GetEarlyAttributeDecodingMembers(name)); } internal override ImmutableArray<NamedTypeSymbol> GetTypeMembersUnordered() { return this.RetargetingTranslator.Retarget(_underlyingType.GetTypeMembersUnordered()); } public override ImmutableArray<NamedTypeSymbol> GetTypeMembers() { return this.RetargetingTranslator.Retarget(_underlyingType.GetTypeMembers()); } public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(ReadOnlyMemory<char> name) { return this.RetargetingTranslator.Retarget(_underlyingType.GetTypeMembers(name)); } public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(ReadOnlyMemory<char> name, int arity) { return this.RetargetingTranslator.Retarget(_underlyingType.GetTypeMembers(name, arity)); } public override Symbol ContainingSymbol { get { return this.RetargetingTranslator.Retarget(_underlyingType.ContainingSymbol); } } public override ImmutableArray<CSharpAttributeData> GetAttributes() { return this.RetargetingTranslator.GetRetargetedAttributes(_underlyingType.GetAttributes(), ref _lazyCustomAttributes); } internal override IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(PEModuleBuilder moduleBuilder) { return this.RetargetingTranslator.RetargetAttributes(_underlyingType.GetCustomAttributesToEmit(moduleBuilder)); } public override AssemblySymbol ContainingAssembly { get { return _retargetingModule.ContainingAssembly; } } internal override ModuleSymbol ContainingModule { get { return _retargetingModule; } } #nullable enable internal override NamedTypeSymbol? LookupMetadataType(ref MetadataTypeName typeName) { NamedTypeSymbol? underlyingResult = _underlyingType.LookupMetadataType(ref typeName); if (underlyingResult is null) { return null; } Debug.Assert(!underlyingResult.IsErrorType()); Debug.Assert((object)_underlyingType == underlyingResult.ContainingSymbol); return this.RetargetingTranslator.Retarget(underlyingResult, RetargetOptions.RetargetPrimitiveTypesByName); } #nullable disable private static ExtendedErrorTypeSymbol CyclicInheritanceError(TypeSymbol declaredBase) { var info = new CSDiagnosticInfo(ErrorCode.ERR_ImportedCircularBase, declaredBase); return new ExtendedErrorTypeSymbol(declaredBase, LookupResultKind.NotReferencable, info, true); } internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics { get { if (ReferenceEquals(_lazyBaseType, ErrorTypeSymbol.UnknownResultType)) { NamedTypeSymbol acyclicBase = GetDeclaredBaseType(null); if ((object)acyclicBase == null) { // if base was not declared, get it from BaseType that should set it to some default var underlyingBase = _underlyingType.BaseTypeNoUseSiteDiagnostics; if ((object)underlyingBase != null) { acyclicBase = this.RetargetingTranslator.Retarget(underlyingBase, RetargetOptions.RetargetPrimitiveTypesByName); } } if ((object)acyclicBase != null && BaseTypeAnalysis.TypeDependsOn(acyclicBase, this)) { return CyclicInheritanceError(acyclicBase); } Interlocked.CompareExchange(ref _lazyBaseType, acyclicBase, ErrorTypeSymbol.UnknownResultType); } return _lazyBaseType; } } internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<TypeSymbol> basesBeingResolved) { if (_lazyInterfaces.IsDefault) { var declaredInterfaces = GetDeclaredInterfaces(basesBeingResolved); if (!IsInterface) { // only interfaces needs to check for inheritance cycles via interfaces. return declaredInterfaces; } ImmutableArray<NamedTypeSymbol> result = declaredInterfaces .SelectAsArray(t => BaseTypeAnalysis.TypeDependsOn(t, this) ? CyclicInheritanceError(t) : t); ImmutableInterlocked.InterlockedCompareExchange(ref _lazyInterfaces, result, default(ImmutableArray<NamedTypeSymbol>)); } return _lazyInterfaces; } internal override ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit() { return this.RetargetingTranslator.Retarget(_underlyingType.GetInterfacesToEmit()); } internal override NamedTypeSymbol GetDeclaredBaseType(ConsList<TypeSymbol> basesBeingResolved) { if (ReferenceEquals(_lazyDeclaredBaseType, ErrorTypeSymbol.UnknownResultType)) { var underlyingBase = _underlyingType.GetDeclaredBaseType(basesBeingResolved); var declaredBase = (object)underlyingBase != null ? this.RetargetingTranslator.Retarget(underlyingBase, RetargetOptions.RetargetPrimitiveTypesByName) : null; Interlocked.CompareExchange(ref _lazyDeclaredBaseType, declaredBase, ErrorTypeSymbol.UnknownResultType); } return _lazyDeclaredBaseType; } internal override ImmutableArray<NamedTypeSymbol> GetDeclaredInterfaces(ConsList<TypeSymbol> basesBeingResolved) { if (_lazyDeclaredInterfaces.IsDefault) { var underlyingBaseInterfaces = _underlyingType.GetDeclaredInterfaces(basesBeingResolved); var result = this.RetargetingTranslator.Retarget(underlyingBaseInterfaces); ImmutableInterlocked.InterlockedCompareExchange(ref _lazyDeclaredInterfaces, result, default(ImmutableArray<NamedTypeSymbol>)); } return _lazyDeclaredInterfaces; } internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo() { if (!_lazyCachedUseSiteInfo.IsInitialized) { AssemblySymbol primaryDependency = PrimaryDependency; _lazyCachedUseSiteInfo.Initialize(primaryDependency, new UseSiteInfo<AssemblySymbol>(primaryDependency).AdjustDiagnosticInfo(CalculateUseSiteDiagnostic())); } return _lazyCachedUseSiteInfo.ToUseSiteInfo(PrimaryDependency); } internal override NamedTypeSymbol ComImportCoClass { get { NamedTypeSymbol coClass = _underlyingType.ComImportCoClass; return (object)coClass == null ? null : this.RetargetingTranslator.Retarget(coClass, RetargetOptions.RetargetPrimitiveTypesByName); } } internal override bool IsComImport { get { return _underlyingType.IsComImport; } } internal sealed override CSharpCompilation DeclaringCompilation // perf, not correctness { get { return null; } } public sealed override bool AreLocalsZeroed { get { throw ExceptionUtilities.Unreachable(); } } internal override bool IsFileLocal => _underlyingType.IsFileLocal; internal override FileIdentifier AssociatedFileIdentifier => _underlyingType.AssociatedFileIdentifier; internal sealed override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable(); internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null; internal sealed override bool IsRecord => _underlyingType.IsRecord; internal sealed override bool IsRecordStruct => _underlyingType.IsRecordStruct; internal sealed override bool HasPossibleWellKnownCloneMethod() => _underlyingType.HasPossibleWellKnownCloneMethod(); internal override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() { foreach ((MethodSymbol body, MethodSymbol implemented) in _underlyingType.SynthesizedInterfaceMethodImpls()) { var newBody = this.RetargetingTranslator.Retarget(body, MemberSignatureComparer.RetargetedExplicitImplementationComparer); var newImplemented = this.RetargetingTranslator.Retarget(implemented, MemberSignatureComparer.RetargetedExplicitImplementationComparer); if (newBody is object && newImplemented is object) { yield return (newBody, newImplemented); } } } internal override bool HasInlineArrayAttribute(out int length) { return _underlyingType.HasInlineArrayAttribute(out length); } #nullable enable internal sealed override bool HasCollectionBuilderAttribute(out TypeSymbol? builderType, out string? methodName) { bool result = _underlyingType.HasCollectionBuilderAttribute(out builderType, out methodName); if (builderType is { }) { builderType = this.RetargetingTranslator.Retarget(builderType, RetargetOptions.RetargetPrimitiveTypesByTypeCode); } return result; } internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? builderArgument) { if (_underlyingType.HasAsyncMethodBuilderAttribute(out builderArgument)) { builderArgument = this.RetargetingTranslator.Retarget(builderArgument, RetargetOptions.RetargetPrimitiveTypesByTypeCode); return true; } builderArgument = null; return false; } internal override bool HasCompilerLoweringPreserveAttribute => _underlyingType.HasCompilerLoweringPreserveAttribute; internal override bool IsUnionTypeCore => _underlyingType.IsUnionTypeCore; internal override string? ExtensionGroupingName => _underlyingType.ExtensionGroupingName; internal override string? ExtensionMarkerName => _underlyingType.ExtensionMarkerName; internal ImmutableArray<(Cci.INestedTypeReference GroupingType, ImmutableArray<Cci.INestedTypeReference> MarkerTypes)> GetExtensionGroupingAndMarkerTypesForTypeForwarding(EmitContext context) { if (_lazyExtensionGroupingAndMarkerTypesForTypeForwarding.IsDefault) { var builder = ArrayBuilder<(Cci.INestedTypeReference GroupingType, ImmutableArray<Cci.INestedTypeReference> MarkerTypes)>.GetInstance(); var markerTypes = ArrayBuilder<Cci.INestedTypeReference>.GetInstance(); ImmutableArray<INestedTypeDefinition> groupingTypes = ((SourceMemberContainerTypeSymbol)_underlyingType).GetExtensionGroupingInfo().GetGroupingTypes(); foreach (var groupingType in groupingTypes) { var retargetedGroupingType = new ForwardedExtensionGroupingOrMarkerType(this.GetCciAdapter(), groupingType); markerTypes.Clear(); foreach (var markerType in groupingType.GetNestedTypes(context)) { markerTypes.Add(new ForwardedExtensionGroupingOrMarkerType(retargetedGroupingType, markerType)); } builder.Add((retargetedGroupingType, markerTypes.ToImmutable())); } markerTypes.Free(); ImmutableInterlocked.InterlockedInitialize(ref _lazyExtensionGroupingAndMarkerTypesForTypeForwarding, builder.ToImmutableAndFree()); } return _lazyExtensionGroupingAndMarkerTypesForTypeForwarding; } /// <summary> /// Used only to point to forwarded types and implements only API surface required to emit information about them. /// </summary> private sealed class ForwardedExtensionGroupingOrMarkerType : Cci.INestedTypeReference { private readonly Cci.ITypeReference _containingType; private readonly Cci.INestedTypeReference _underlying; public ForwardedExtensionGroupingOrMarkerType(Cci.ITypeReference containingType, Cci.INestedTypeReference underlying) { _containingType = containingType; _underlying = underlying; } bool INestedTypeReference.InheritsEnclosingTypeTypeParameters => throw ExceptionUtilities.Unreachable(); ushort INamedTypeReference.GenericParameterCount => _underlying.GenericParameterCount; bool INamedTypeReference.MangleName => _underlying.MangleName; string? INamedTypeReference.AssociatedFileIdentifier => _underlying.AssociatedFileIdentifier; bool ITypeReference.IsEnum => throw ExceptionUtilities.Unreachable(); bool ITypeReference.IsValueType => throw ExceptionUtilities.Unreachable(); Cci.PrimitiveTypeCode ITypeReference.TypeCode => throw ExceptionUtilities.Unreachable(); TypeDefinitionHandle ITypeReference.TypeDef => throw ExceptionUtilities.Unreachable(); IGenericMethodParameterReference? ITypeReference.AsGenericMethodParameterReference => null; IGenericTypeInstanceReference? ITypeReference.AsGenericTypeInstanceReference => null; IGenericTypeParameterReference? ITypeReference.AsGenericTypeParameterReference => null; INamespaceTypeReference? ITypeReference.AsNamespaceTypeReference => null; INestedTypeReference? ITypeReference.AsNestedTypeReference => this; ISpecializedNestedTypeReference? ITypeReference.AsSpecializedNestedTypeReference => null; string? INamedEntity.Name => _underlying.Name; IDefinition? IReference.AsDefinition(EmitContext context) => null; INamespaceTypeDefinition? ITypeReference.AsNamespaceTypeDefinition(EmitContext context) => null; INestedTypeDefinition? ITypeReference.AsNestedTypeDefinition(EmitContext context) => null; ITypeDefinition? ITypeReference.AsTypeDefinition(EmitContext context) => null; void IReference.Dispatch(MetadataVisitor visitor) { throw ExceptionUtilities.Unreachable(); } IEnumerable<ICustomAttribute> IReference.GetAttributes(EmitContext context) { throw ExceptionUtilities.Unreachable(); } ITypeReference ITypeMemberReference.GetContainingType(EmitContext context) => _containingType; ISymbolInternal? IReference.GetInternalSymbol() => null; ITypeDefinition? ITypeReference.GetResolvedType(EmitContext context) => null; } } }