| File: Symbols\Retargeting\RetargetingModuleSymbol.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.Diagnostics; using System.Globalization; using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; using System.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting { /// <summary> /// Represents a primary module of a <see cref="RetargetingAssemblySymbol"/>. Essentially this is a wrapper around /// another <see cref="SourceModuleSymbol"/> that is responsible for retargeting symbols from one assembly to another. /// It can retarget symbols for multiple assemblies at the same time. /// /// Here is how retargeting is implemented in general: /// - Symbols from underlying module are substituted with retargeting symbols. /// - Symbols from referenced assemblies that can be reused as is (i.e. don'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 partial class RetargetingModuleSymbol : NonMissingModuleSymbol { /// <summary> /// Owning <see cref="RetargetingAssemblySymbol"/>. /// </summary> private readonly RetargetingAssemblySymbol _retargetingAssembly; /// <summary> /// The underlying <see cref="ModuleSymbol"/>, cannot be another <see cref="RetargetingModuleSymbol"/>. /// </summary> private readonly SourceModuleSymbol _underlyingModule; /// <summary> /// The map that captures information about what assembly should be retargeted /// to what assembly. Key is the <see cref="AssemblySymbol"/> referenced by the underlying module, /// value is the corresponding <see cref="AssemblySymbol"/> referenced by this module, and corresponding /// retargeting map for symbols. /// </summary> private readonly Dictionary<AssemblySymbol, DestinationData> _retargetingAssemblyMap = new Dictionary<AssemblySymbol, DestinationData>(); #nullable enable private struct DestinationData { public AssemblySymbol To; private ConcurrentDictionary<NamedTypeSymbol, NamedTypeSymbol>? _symbolMap; public ConcurrentDictionary<NamedTypeSymbol, NamedTypeSymbol> SymbolMap => LazyInitializer.EnsureInitialized(ref _symbolMap); } #nullable disable internal readonly RetargetingSymbolTranslator RetargetingTranslator; /// <summary> /// Retargeted custom attributes /// </summary> private ImmutableArray<CSharpAttributeData> _lazyCustomAttributes; /// <summary> /// Constructor. /// </summary> /// <param name="retargetingAssembly"> /// Owning assembly. /// </param> /// <param name="underlyingModule"> /// The underlying ModuleSymbol, cannot be another RetargetingModuleSymbol. /// </param> public RetargetingModuleSymbol(RetargetingAssemblySymbol retargetingAssembly, SourceModuleSymbol underlyingModule) { Debug.Assert((object)retargetingAssembly != null); Debug.Assert((object)underlyingModule != null); _retargetingAssembly = retargetingAssembly; _underlyingModule = underlyingModule; this.RetargetingTranslator = new RetargetingSymbolTranslator(this); _createRetargetingMethod = CreateRetargetingMethod; _createRetargetingNamespace = CreateRetargetingNamespace; _createRetargetingNamedType = CreateRetargetingNamedType; _createRetargetingField = CreateRetargetingField; _createRetargetingProperty = CreateRetargetingProperty; _createRetargetingEvent = CreateRetargetingEvent; _createRetargetingTypeParameter = CreateRetargetingTypeParameter; } internal override int Ordinal { get { Debug.Assert(_underlyingModule.Ordinal == 0); // Always a source module return 0; } } internal override Machine Machine { get { return _underlyingModule.Machine; } } internal override bool Bit32Required { get { return _underlyingModule.Bit32Required; } } /// <summary> /// The underlying ModuleSymbol, cannot be another RetargetingModuleSymbol. /// </summary> public SourceModuleSymbol UnderlyingModule { get { return _underlyingModule; } } public override NamespaceSymbol GlobalNamespace { get { return RetargetingTranslator.Retarget(_underlyingModule.GlobalNamespace); } } public override bool IsImplicitlyDeclared { get { return _underlyingModule.IsImplicitlyDeclared; } } public override string Name { get { return _underlyingModule.Name; } } public override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)) { return _underlyingModule.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); } public override Symbol ContainingSymbol { get { return _retargetingAssembly; } } public override AssemblySymbol ContainingAssembly { get { return _retargetingAssembly; } } public override ImmutableArray<Location> Locations { get { return _underlyingModule.Locations; } } /// <summary> /// A helper method for ReferenceManager to set AssemblySymbols for assemblies /// referenced by this module. /// </summary> internal override void SetReferences(ModuleReferences<AssemblySymbol> moduleReferences, SourceAssemblySymbol originatingSourceAssemblyDebugOnly) { base.SetReferences(moduleReferences, originatingSourceAssemblyDebugOnly); // Build the retargeting map _retargetingAssemblyMap.Clear(); ImmutableArray<AssemblySymbol> underlyingBoundReferences = _underlyingModule.GetReferencedAssemblySymbols(); ImmutableArray<AssemblySymbol> referencedAssemblySymbols = moduleReferences.Symbols; Debug.Assert(referencedAssemblySymbols.Length == moduleReferences.Identities.Length); Debug.Assert(referencedAssemblySymbols.Length <= underlyingBoundReferences.Length); // Linked references are filtered out. int i, j; for (i = 0, j = 0; i < referencedAssemblySymbols.Length; i++, j++) { // Skip linked assemblies for source module while (underlyingBoundReferences[j].IsLinked) { j++; } #if DEBUG var identityComparer = _underlyingModule.DeclaringCompilation.Options.AssemblyIdentityComparer; var definitionIdentity = ReferenceEquals(referencedAssemblySymbols[i], originatingSourceAssemblyDebugOnly) ? new AssemblyIdentity(name: originatingSourceAssemblyDebugOnly.Name) : referencedAssemblySymbols[i].Identity; Debug.Assert(identityComparer.Compare(moduleReferences.Identities[i], definitionIdentity) != AssemblyIdentityComparer.ComparisonResult.NotEquivalent); Debug.Assert(identityComparer.Compare(moduleReferences.Identities[i], underlyingBoundReferences[j].Identity) != AssemblyIdentityComparer.ComparisonResult.NotEquivalent); #endif if (!ReferenceEquals(referencedAssemblySymbols[i], underlyingBoundReferences[j])) { DestinationData destinationData; if (!_retargetingAssemblyMap.TryGetValue(underlyingBoundReferences[j], out destinationData)) { _retargetingAssemblyMap.Add(underlyingBoundReferences[j], new DestinationData { To = referencedAssemblySymbols[i] }); } else { Debug.Assert(ReferenceEquals(destinationData.To, referencedAssemblySymbols[i])); } } } #if DEBUG while (j < underlyingBoundReferences.Length && underlyingBoundReferences[j].IsLinked) { j++; } Debug.Assert(j == underlyingBoundReferences.Length); #endif } internal bool RetargetingDefinitions(AssemblySymbol from, out AssemblySymbol to) { DestinationData destination; if (!_retargetingAssemblyMap.TryGetValue(from, out destination)) { to = null; return false; } to = destination.To; return true; } internal override ICollection<string> TypeNames { get { return _underlyingModule.TypeNames; } } internal override ICollection<string> NamespaceNames { get { return _underlyingModule.NamespaceNames; } } public override ImmutableArray<CSharpAttributeData> GetAttributes() { return RetargetingTranslator.GetRetargetedAttributes(_underlyingModule.GetAttributes(), ref _lazyCustomAttributes); } internal override bool HasAssemblyCompilationRelaxationsAttribute { get { return _underlyingModule.HasAssemblyCompilationRelaxationsAttribute; } } internal override bool HasAssemblyRuntimeCompatibilityAttribute { get { return _underlyingModule.HasAssemblyRuntimeCompatibilityAttribute; } } internal override CharSet? DefaultMarshallingCharSet { get { return _underlyingModule.DefaultMarshallingCharSet; } } internal sealed override CSharpCompilation DeclaringCompilation // perf, not correctness { get { return null; } } public override ModuleMetadata GetMetadata() => _underlyingModule.GetMetadata(); public sealed override bool AreLocalsZeroed { get { throw ExceptionUtilities.Unreachable(); } } internal override bool UseUpdatedEscapeRules => _underlyingModule.UseUpdatedEscapeRules; internal override bool UseUpdatedMemorySafetyRules => _underlyingModule.UseUpdatedMemorySafetyRules; #nullable enable internal sealed override ObsoleteAttributeData? ObsoleteAttributeData => _underlyingModule.ObsoleteAttributeData; } }