File: Symbols\NonMissingModuleSymbol.cs
Web Access
Project: src\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.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// A <see cref="NonMissingModuleSymbol"/> is a special kind of <see cref="ModuleSymbol"/> that represents
    /// a module that is not missing, i.e. the "real" thing.
    /// </summary>
    internal abstract class NonMissingModuleSymbol : ModuleSymbol
    {
        /// <summary>
        /// An array of <see cref="AssemblySymbol"/> objects corresponding to assemblies directly referenced by this module.
        /// </summary>
        /// <remarks>
        /// The contents are provided by ReferenceManager and may not be modified.
        /// </remarks>
        private ModuleReferences<AssemblySymbol> _moduleReferences;
 
        /// <summary>
        /// Does this symbol represent a missing module.
        /// </summary>
        internal sealed override bool IsMissing
        {
            get
            {
                return false;
            }
        }
 
        /// <summary>
        /// Returns an array of assembly identities for assemblies referenced by this module.
        /// Items at the same position from GetReferencedAssemblies and from GetReferencedAssemblySymbols 
        /// should correspond to each other.
        /// </summary>
        internal sealed override ImmutableArray<AssemblyIdentity> GetReferencedAssemblies()
        {
            AssertReferencesInitialized();
            return _moduleReferences.Identities;
        }
 
        /// <summary>
        /// Returns an array of AssemblySymbol objects corresponding to assemblies referenced 
        /// by this module. Items at the same position from GetReferencedAssemblies and 
        /// from GetReferencedAssemblySymbols should correspond to each other. If reference is 
        /// not resolved by compiler, GetReferencedAssemblySymbols returns MissingAssemblySymbol in the
        /// corresponding item.
        /// </summary>
        internal sealed override ImmutableArray<AssemblySymbol> GetReferencedAssemblySymbols()
        {
            AssertReferencesInitialized();
            return _moduleReferences.Symbols;
        }
 
        internal ImmutableArray<UnifiedAssembly<AssemblySymbol>> GetUnifiedAssemblies()
        {
            AssertReferencesInitialized();
            return _moduleReferences.UnifiedAssemblies;
        }
 
        internal override bool HasUnifiedReferences
        {
            get { return GetUnifiedAssemblies().Length > 0; }
        }
 
        internal override bool GetUnificationUseSiteDiagnostic(ref DiagnosticInfo result, TypeSymbol dependentType)
        {
            AssertReferencesInitialized();
 
            var ownerModule = this;
            var ownerAssembly = ownerModule.ContainingAssembly;
            var dependentAssembly = dependentType.ContainingAssembly;
            if (ownerAssembly == dependentAssembly)
            {
                return false;
            }
 
            // TODO (tomat): we should report an error/warning for all unified references, not just the first one.
 
            foreach (var unifiedAssembly in GetUnifiedAssemblies())
            {
                if (!ReferenceEquals(unifiedAssembly.TargetAssembly, dependentAssembly))
                {
                    continue;
                }
 
                var referenceId = unifiedAssembly.OriginalReference;
                var definitionId = dependentAssembly.Identity;
                var involvedAssemblies = ImmutableArray.Create<Symbol>(ownerAssembly, dependentAssembly);
 
                DiagnosticInfo info;
                if (definitionId.Version > referenceId.Version)
                {
                    // unified with a definition whose version is higher than the reference                    
                    ErrorCode warning = (definitionId.Version.Major == referenceId.Version.Major && definitionId.Version.Minor == referenceId.Version.Minor) ?
                                        ErrorCode.WRN_UnifyReferenceBldRev : ErrorCode.WRN_UnifyReferenceMajMin;
 
                    // warning: Assuming assembly reference '{0}' used by '{1}' matches identity '{2}' of '{3}', you may need to supply runtime policy.
                    info = new CSDiagnosticInfo(
                        warning,
                        new object[]
                        {
                            referenceId.GetDisplayName(),
                            ownerAssembly.Name, // TODO (tomat): should rather be MetadataReference.Display for the corresponding reference
                            definitionId.GetDisplayName(),
                            dependentAssembly.Name
                        },
                        involvedAssemblies,
                        ImmutableArray<Location>.Empty);
                }
                else
                {
                    // unified with a definition whose version is lower than the reference
 
                    // error: Assembly '{0}' with identity '{1}' uses '{2}' which has a higher version than referenced assembly '{3}' with identity '{4}'
                    info = new CSDiagnosticInfo(
                        ErrorCode.ERR_AssemblyMatchBadVersion,
                        new object[]
                        {
                            ownerAssembly.Name, // TODO (tomat): should rather be MetadataReference.Display for the corresponding reference
                            ownerAssembly.Identity.GetDisplayName(),
                            referenceId.GetDisplayName(),
                            dependentAssembly.Name, // TODO (tomat): should rather be MetadataReference.Display for the corresponding reference
                            definitionId.GetDisplayName()
                        },
                        involvedAssemblies,
                        ImmutableArray<Location>.Empty);
                }
 
                if (MergeUseSiteDiagnostics(ref result, info))
                {
                    return true;
                }
            }
 
            return false;
        }
 
        /// <summary>
        /// A helper method for ReferenceManager to set assembly identities for assemblies 
        /// referenced by this module and corresponding AssemblySymbols.
        /// </summary>
        internal override void SetReferences(ModuleReferences<AssemblySymbol> moduleReferences, SourceAssemblySymbol originatingSourceAssemblyDebugOnly = null)
        {
            Debug.Assert(moduleReferences != null);
 
            AssertReferencesUninitialized();
 
            _moduleReferences = moduleReferences;
        }
 
        [Conditional("DEBUG")]
        internal void AssertReferencesUninitialized()
        {
            Debug.Assert(_moduleReferences == null);
        }
 
        [Conditional("DEBUG")]
        internal void AssertReferencesInitialized()
        {
            Debug.Assert(_moduleReferences != null);
        }
 
#nullable enable 
 
        /// <summary>
        /// Lookup a top level type referenced from metadata, names should be
        /// compared case-sensitively.
        /// </summary>
        /// <param name="emittedName">
        /// Full type name, possibly with generic name mangling.
        /// </param>
        /// <returns>
        /// Symbol for the type, or null if the type isn't found.
        /// </returns>
        /// <remarks></remarks>
        internal sealed override NamedTypeSymbol? LookupTopLevelMetadataType(ref MetadataTypeName emittedName)
        {
            NamedTypeSymbol? result;
            NamespaceSymbol? scope = this.GlobalNamespace.LookupNestedNamespace(emittedName.NamespaceSegmentsMemory);
 
            if ((object?)scope == null)
            {
                // We failed to locate the namespace
                result = null;
            }
            else
            {
                result = scope.LookupMetadataType(ref emittedName);
            }
 
            Debug.Assert(result?.IsErrorType() != true);
            return result;
        }
    }
}