| File: Symbols\Retargeting\RetargetingAssemblySymbol.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.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Collections.ObjectModel; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using System.Diagnostics; using System.Globalization; using System.Threading; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting { /// <summary> /// Essentially this is a wrapper around another AssemblySymbol that is responsible for retargeting /// symbols from one assembly to another. It can retarget symbols for multiple assemblies at the same time. /// /// For example, compilation C1 references v1 of Lib.dll and compilation C2 references C1 and v2 of Lib.dll. /// In this case, in context of C2, all types from v1 of Lib.dll leaking through C1 (through method /// signatures, etc.) must be retargeted to the types from v2 of Lib.dll. This is what /// RetargetingAssemblySymbol is responsible for. In the example above, modules in C2 do not /// reference C1.m_AssemblySymbol, but reference a special RetargetingAssemblySymbol created for /// C1 by ReferenceManager. /// /// Here is how retargeting is implemented in general: /// - Symbols from underlying assembly are substituted with retargeting symbols. /// - Symbols from referenced assemblies that can be reused as is (i.e. doesn't have to be retargeted) are /// used as is. /// - Symbols from referenced assemblies that must be retargeted are substituted with result of retargeting. /// </summary> internal sealed class RetargetingAssemblySymbol : MetadataOrSourceOrRetargetingAssemblySymbol { /// <summary> /// The underlying AssemblySymbol, it leaks symbols that should be retargeted. /// This cannot be an instance of RetargetingAssemblySymbol. /// </summary> private readonly SourceAssemblySymbol _underlyingAssembly; /// <summary> /// The list of contained ModuleSymbol objects. First item in the list /// is RetargetingModuleSymbol that wraps corresponding SourceModuleSymbol /// from underlyingAssembly.Modules list, the rest are PEModuleSymbols for /// added modules. /// </summary> private readonly ImmutableArray<ModuleSymbol> _modules; /// <summary> /// An array of assemblies involved in canonical type resolution of /// NoPia local types defined within this assembly. In other words, all /// references used by a compilation referencing this assembly. /// The array and its content is provided by ReferenceManager and must not be modified. /// </summary> private ImmutableArray<AssemblySymbol> _noPiaResolutionAssemblies; /// <summary> /// An array of assemblies referenced by this assembly, which are linked (/l-ed) by /// each compilation that is using this AssemblySymbol as a reference. /// If this AssemblySymbol is linked too, it will be in this array too. /// The array and its content is provided by ReferenceManager and must not be modified. /// </summary> private ImmutableArray<AssemblySymbol> _linkedReferencedAssemblies; /// <summary> /// Backing field for the map from a local NoPia type to corresponding canonical type. /// </summary> private ConcurrentDictionary<NamedTypeSymbol, NamedTypeSymbol> _noPiaUnificationMap; /// <summary> /// A map from a local NoPia type to corresponding canonical type. /// </summary> internal ConcurrentDictionary<NamedTypeSymbol, NamedTypeSymbol> NoPiaUnificationMap => LazyInitializer.EnsureInitialized(ref _noPiaUnificationMap, () => new ConcurrentDictionary<NamedTypeSymbol, NamedTypeSymbol>(concurrencyLevel: 2, capacity: 0)); /// <summary> /// Assembly is /l-ed by compilation that is using it as a reference. /// </summary> private readonly bool _isLinked; /// <summary> /// Retargeted custom attributes /// </summary> private ImmutableArray<CSharpAttributeData> _lazyCustomAttributes; /// <summary> /// Constructor. /// </summary> /// <param name="underlyingAssembly"> /// The underlying AssemblySymbol, cannot be an instance of RetargetingAssemblySymbol. /// </param> /// <param name="isLinked"> /// Assembly is /l-ed by compilation that is using it as a reference. /// </param> public RetargetingAssemblySymbol(SourceAssemblySymbol underlyingAssembly, bool isLinked) { Debug.Assert((object)underlyingAssembly != null); _underlyingAssembly = underlyingAssembly; ModuleSymbol[] modules = new ModuleSymbol[underlyingAssembly.Modules.Length]; modules[0] = new RetargetingModuleSymbol(this, (SourceModuleSymbol)underlyingAssembly.Modules[0]); for (int i = 1; i < underlyingAssembly.Modules.Length; i++) { PEModuleSymbol under = (PEModuleSymbol)underlyingAssembly.Modules[i]; modules[i] = new PEModuleSymbol(this, under.Module, under.ImportOptions, i); } _modules = modules.AsImmutableOrNull(); _isLinked = isLinked; } private RetargetingModuleSymbol.RetargetingSymbolTranslator RetargetingTranslator { get { return ((RetargetingModuleSymbol)_modules[0]).RetargetingTranslator; } } /// <summary> /// The underlying <see cref="SourceAssemblySymbol"/>. /// </summary> public SourceAssemblySymbol UnderlyingAssembly { get { return _underlyingAssembly; } } public override bool IsImplicitlyDeclared { get { return _underlyingAssembly.IsImplicitlyDeclared; } } public override AssemblyIdentity Identity { get { return _underlyingAssembly.Identity; } } public override Version AssemblyVersionPattern => _underlyingAssembly.AssemblyVersionPattern; internal override ImmutableArray<byte> PublicKey { get { return _underlyingAssembly.PublicKey; } } public override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)) { return _underlyingAssembly.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); } public override ImmutableArray<ModuleSymbol> Modules { get { return _modules; } } internal override bool KeepLookingForDeclaredSpecialTypes { get { // RetargetingAssemblySymbol never represents Core library. return false; } } public override ImmutableArray<Location> Locations { get { return _underlyingAssembly.Locations; } } internal override bool HasImportedFromTypeLibAttribute => _underlyingAssembly.HasImportedFromTypeLibAttribute; internal override bool HasPrimaryInteropAssemblyAttribute => _underlyingAssembly.HasPrimaryInteropAssemblyAttribute; internal override IEnumerable<ImmutableArray<byte>> GetInternalsVisibleToPublicKeys(string simpleName) { return _underlyingAssembly.GetInternalsVisibleToPublicKeys(simpleName); } internal override IEnumerable<string> GetInternalsVisibleToAssemblyNames() { return _underlyingAssembly.GetInternalsVisibleToAssemblyNames(); } internal override bool AreInternalsVisibleToThisAssembly(AssemblySymbol potentialGiverOfAccess) { IVTConclusion conclusion; if (!AssembliesToWhichInternalAccessHasBeenDetermined.TryGetValue(potentialGiverOfAccess, out conclusion)) { conclusion = _underlyingAssembly.MakeFinalIVTDetermination(potentialGiverOfAccess, assertUnexpectedGiver: false); if (IsDirectlyOrIndirectlyReferenced(potentialGiverOfAccess)) { AssembliesToWhichInternalAccessHasBeenDetermined.TryAdd(potentialGiverOfAccess, conclusion); } else { Debug.Fail("We are performing a check for an unrelated assembly which likely indicates a bug."); } } return conclusion == IVTConclusion.Match || conclusion == IVTConclusion.OneSignedOneNot; } public override ImmutableArray<CSharpAttributeData> GetAttributes() { return RetargetingTranslator.GetRetargetedAttributes(_underlyingAssembly.GetAttributes(), ref _lazyCustomAttributes); } /// <summary> /// Lookup declaration for FX type in this Assembly. /// </summary> /// <param name="type"></param> /// <returns></returns> /// <remarks></remarks> internal override NamedTypeSymbol GetDeclaredSpecialType(ExtendedSpecialType type) { // Cor library should not have any references and, therefore, should never be // wrapped by a RetargetingAssemblySymbol. throw ExceptionUtilities.Unreachable(); } internal override ImmutableArray<AssemblySymbol> GetNoPiaResolutionAssemblies() { return _noPiaResolutionAssemblies; } internal override void SetNoPiaResolutionAssemblies(ImmutableArray<AssemblySymbol> assemblies) { _noPiaResolutionAssemblies = assemblies; } internal override void SetLinkedReferencedAssemblies(ImmutableArray<AssemblySymbol> assemblies) { _linkedReferencedAssemblies = assemblies; } internal override ImmutableArray<AssemblySymbol> GetLinkedReferencedAssemblies() { return _linkedReferencedAssemblies; } internal override bool IsLinked { get { return _isLinked; } } public override ICollection<string> TypeNames { get { return _underlyingAssembly.TypeNames; } } public override ICollection<string> NamespaceNames { get { return _underlyingAssembly.NamespaceNames; } } public override bool MightContainExtensions { get { return _underlyingAssembly.MightContainExtensions; } } internal sealed override CSharpCompilation DeclaringCompilation // perf, not correctness { get { return null; } } internal override TypeConversions TypeConversions => CorLibrary.TypeConversions; internal override bool GetGuidString(out string guidString) { return _underlyingAssembly.GetGuidString(out guidString); } #nullable enable internal sealed override ObsoleteAttributeData? ObsoleteAttributeData => _underlyingAssembly.ObsoleteAttributeData; internal override NamedTypeSymbol? TryLookupForwardedMetadataTypeWithCycleDetection(ref MetadataTypeName emittedName, ConsList<AssemblySymbol>? visitedAssemblies) { NamedTypeSymbol? underlying = _underlyingAssembly.TryLookupForwardedMetadataTypeWithCycleDetection(ref emittedName, visitedAssemblies: null); if ((object?)underlying == null) { return null; } return this.RetargetingTranslator.Retarget(underlying, RetargetOptions.RetargetPrimitiveTypesByName); } #nullable disable internal override IEnumerable<NamedTypeSymbol> GetAllTopLevelForwardedTypes() { foreach (NamedTypeSymbol underlying in _underlyingAssembly.GetAllTopLevelForwardedTypes()) { yield return this.RetargetingTranslator.Retarget(underlying, RetargetOptions.RetargetPrimitiveTypesByName); } } public override AssemblyMetadata GetMetadata() => _underlyingAssembly.GetMetadata(); } }