File: Symbols\Source\SourceAssemblySymbol.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;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Symbols;
using Roslyn.Utilities;
using CommonAssemblyWellKnownAttributeData = Microsoft.CodeAnalysis.CommonAssemblyWellKnownAttributeData<Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol>;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// Represents an assembly built by compiler.
    /// </summary>
    internal sealed partial class SourceAssemblySymbol : MetadataOrSourceAssemblySymbol, ISourceAssemblySymbolInternal, IAttributeTargetSymbol
    {
        /// <summary>
        /// A Compilation the assembly is created for.
        /// </summary>
        private readonly CSharpCompilation _compilation;
 
        private SymbolCompletionState _state;
 
        /// <summary>
        /// Assembly's identity.
        /// </summary>
        internal AssemblyIdentity lazyAssemblyIdentity;
        private readonly string _assemblySimpleName;
 
        // Computing the identity requires computing the public key. Computing the public key 
        // can require binding attributes that contain version or strong name information. 
        // Attribute binding will check type visibility which will possibly 
        // check IVT relationships. To correctly determine the IVT relationship requires the public key. 
        // To avoid infinite recursion, this type notes, per thread, the assembly for which the thread 
        // is actively computing the public key (assemblyForWhichCurrentThreadIsComputingKeys). Should a request to determine IVT
        // relationship occur on the thread that is computing the public key, access is optimistically
        // granted provided the simple assembly names match. When such access is granted
        // the assembly to which we have been granted access is noted (optimisticallyGrantedInternalsAccess).
        // After the public key has been computed, the set of optimistic grants is reexamined 
        // to ensure that full identities match. This may produce diagnostics.
        private StrongNameKeys _lazyStrongNameKeys;
 
        /// <summary>
        /// A list of modules the assembly consists of. 
        /// The first (index=0) module is a SourceModuleSymbol, which is a primary module, the rest are net-modules.
        /// </summary>
        private readonly ImmutableArray<ModuleSymbol> _modules;
 
        /// <summary>
        /// Bag of assembly's custom attributes and decoded well-known attribute data from source.
        /// </summary>
        private CustomAttributesBag<CSharpAttributeData> _lazySourceAttributesBag;
 
        /// <summary>
        /// Bag of assembly's custom attributes and decoded well-known attribute data from added netmodules.
        /// </summary>
        private CustomAttributesBag<CSharpAttributeData> _lazyNetModuleAttributesBag;
 
#nullable enable 
 
        private IDictionary<string, NamedTypeSymbol> _lazyForwardedTypesFromSource;
 
#nullable disable
 
        /// <summary>
        /// Indices of attributes that will not be emitted for one of two reasons:
        /// - They are duplicates of another attribute (i.e. attributes that bind to the same constructor and have identical arguments)
        /// - They are InternalsVisibleToAttributes with invalid assembly identities
        /// </summary>
        /// <remarks>
        /// These indices correspond to the merged assembly attributes from source and added net modules, i.e. attributes returned by <see cref="GetAttributes"/> method.
        /// </remarks>
        private ConcurrentSet<int> _lazyOmittedAttributeIndices;
 
        private ThreeState _lazyContainsExtensionMethods;
 
        /// <summary>
        /// Map for storing effectively private or effectively internal fields declared in this assembly but never initialized nor assigned.
        /// Each {symbol, bool} key-value pair in this map indicates the following:
        ///  (a) Key: Unassigned field symbol.
        ///  (b) Value: True if the unassigned field is effectively internal, false otherwise.
        /// </summary>
        private readonly ConcurrentDictionary<FieldSymbol, bool> _unassignedFieldsMap = new ConcurrentDictionary<FieldSymbol, bool>();
 
        /// <summary>
        /// private fields declared in this assembly but never read
        /// </summary>
        private readonly ConcurrentSet<FieldSymbol> _unreadFields = new ConcurrentSet<FieldSymbol>();
 
        /// <summary>
        /// We imitate the native compiler's policy of not warning about unused fields
        /// when the enclosing type is used by an extern method for a ref argument.
        /// Here we keep track of those types.
        /// </summary>
        internal ConcurrentSet<TypeSymbol> TypesReferencedInExternalMethods = new ConcurrentSet<TypeSymbol>();
 
        /// <summary>
        /// The warnings for unused fields.
        /// </summary>
        private ImmutableArray<Diagnostic> _unusedFieldWarnings;
 
        internal SourceAssemblySymbol(
            CSharpCompilation compilation,
            string assemblySimpleName,
            string moduleName,
            ImmutableArray<PEModule> netModules)
        {
            Debug.Assert(compilation != null);
            Debug.Assert(assemblySimpleName != null);
            Debug.Assert(!String.IsNullOrWhiteSpace(moduleName));
            Debug.Assert(!netModules.IsDefault);
 
            _compilation = compilation;
            _assemblySimpleName = assemblySimpleName;
 
            ArrayBuilder<ModuleSymbol> moduleBuilder = new ArrayBuilder<ModuleSymbol>(1 + netModules.Length);
 
            moduleBuilder.Add(new SourceModuleSymbol(this, compilation.Declarations, moduleName));
 
            var importOptions = (compilation.Options.MetadataImportOptions == MetadataImportOptions.All) ?
                MetadataImportOptions.All : MetadataImportOptions.Internal;
 
            foreach (PEModule netModule in netModules)
            {
                moduleBuilder.Add(new PEModuleSymbol(this, netModule, importOptions, moduleBuilder.Count));
                // SetReferences will be called later by the ReferenceManager (in CreateSourceAssemblyFullBind for 
                // a fresh manager, in CreateSourceAssemblyReuseData for a reused one).
            }
 
            _modules = moduleBuilder.ToImmutableAndFree();
 
            if (!compilation.Options.CryptoPublicKey.IsEmpty)
            {
                // Private key is not necessary for assembly identity, only when emitting.  For this reason, the private key can remain null.
                _lazyStrongNameKeys = StrongNameKeys.Create(compilation.Options.CryptoPublicKey, privateKey: null, hasCounterSignature: false, MessageProvider.Instance);
            }
        }
 
        public override string Name
        {
            get
            {
                return _assemblySimpleName;
            }
        }
 
        /// <remarks>
        /// This override is essential - it's a base case of the recursive definition.
        /// </remarks>
        internal sealed override CSharpCompilation DeclaringCompilation
        {
            get
            {
                return _compilation;
            }
        }
 
        public override bool IsInteractive
        {
            get
            {
                return _compilation.IsSubmission;
            }
        }
 
        internal bool MightContainNoPiaLocalTypes()
        {
            for (int i = 1; i < _modules.Length; i++)
            {
                var peModuleSymbol = (Metadata.PE.PEModuleSymbol)_modules[i];
                if (peModuleSymbol.Module.ContainsNoPiaLocalTypes())
                {
                    return true;
                }
            }
 
            return SourceModule.MightContainNoPiaLocalTypes();
        }
 
        public override AssemblyIdentity Identity
        {
            get
            {
                if (lazyAssemblyIdentity == null)
                    Interlocked.CompareExchange(ref lazyAssemblyIdentity, ComputeIdentity(), null);
 
                return lazyAssemblyIdentity;
            }
        }
 
        internal override bool HasImportedFromTypeLibAttribute
            => GetSourceDecodedWellKnownAttributeData()?.HasImportedFromTypeLibAttribute == true;
 
        internal override bool HasPrimaryInteropAssemblyAttribute
            => GetSourceDecodedWellKnownAttributeData()?.HasPrimaryInteropAssemblyAttribute == true;
 
        internal override Symbol GetSpecialTypeMember(SpecialMember member)
        {
            return _compilation.IsMemberMissing(member) ? null : base.GetSpecialTypeMember(member);
        }
 
#nullable enable
        private string? GetWellKnownAttributeDataStringField(Func<CommonAssemblyWellKnownAttributeData, string> fieldGetter, string? missingValue = null, QuickAttributes? attributeMatchesOpt = null)
        {
            string? fieldValue = missingValue;
 
            var data = attributeMatchesOpt is null
                ? GetSourceDecodedWellKnownAttributeData()
                : GetSourceDecodedWellKnownAttributeData(attributeMatchesOpt.Value);
 
            if (data != null)
            {
                fieldValue = fieldGetter(data);
            }
 
            if (fieldValue == (object?)missingValue)
            {
                data = (attributeMatchesOpt is null || _lazyNetModuleAttributesBag is not null)
                    ? GetNetModuleDecodedWellKnownAttributeData()
                    : GetLimitedNetModuleDecodedWellKnownAttributeData(attributeMatchesOpt.Value);
 
                if (data != null)
                {
                    fieldValue = fieldGetter(data);
                }
            }
 
            return fieldValue;
        }
#nullable disable
 
        internal bool RuntimeCompatibilityWrapNonExceptionThrows
        {
            get
            {
                var data = GetSourceDecodedWellKnownAttributeData() ?? GetNetModuleDecodedWellKnownAttributeData();
 
                // By default WrapNonExceptionThrows is considered to be true.
                return (data != null) ? data.RuntimeCompatibilityWrapNonExceptionThrows : CommonAssemblyWellKnownAttributeData.WrapNonExceptionThrowsDefault;
            }
        }
 
        internal string FileVersion
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyFileVersionAttributeSetting);
            }
        }
 
        internal string Title
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyTitleAttributeSetting);
            }
        }
 
        internal string Description
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyDescriptionAttributeSetting);
            }
        }
 
        internal string Company
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyCompanyAttributeSetting);
            }
        }
 
        internal string Product
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyProductAttributeSetting);
            }
        }
 
        internal string InformationalVersion
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyInformationalVersionAttributeSetting);
            }
        }
 
        internal string Copyright
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyCopyrightAttributeSetting);
            }
        }
 
        internal string Trademark
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyTrademarkAttributeSetting);
            }
        }
 
        private ThreeState AssemblyDelaySignAttributeSetting
        {
            get
            {
                var defaultValue = ThreeState.Unknown;
                var fieldValue = defaultValue;
 
                var data = GetSourceDecodedWellKnownAttributeData();
                if (data != null)
                {
                    fieldValue = data.AssemblyDelaySignAttributeSetting;
                }
 
                if (fieldValue == defaultValue)
                {
                    data = GetNetModuleDecodedWellKnownAttributeData();
                    if (data != null)
                    {
                        fieldValue = data.AssemblyDelaySignAttributeSetting;
                    }
                }
 
                return fieldValue;
            }
        }
 
        private string AssemblyKeyContainerAttributeSetting
        {
            get
            {
                // We mitigate circularity problems by only actively loading attributes that pass a syntactic check
                return GetWellKnownAttributeDataStringField(data => data.AssemblyKeyContainerAttributeSetting,
                    WellKnownAttributeData.StringMissingValue, QuickAttributes.AssemblyKeyName);
            }
        }
 
        private string AssemblyKeyFileAttributeSetting
        {
            get
            {
                // We mitigate circularity problems by only actively loading attributes that pass a syntactic check
                return GetWellKnownAttributeDataStringField(data => data.AssemblyKeyFileAttributeSetting,
                    WellKnownAttributeData.StringMissingValue, QuickAttributes.AssemblyKeyFile);
            }
        }
 
        private string AssemblyCultureAttributeSetting
        {
            get
            {
                return GetWellKnownAttributeDataStringField(data => data.AssemblyCultureAttributeSetting);
            }
        }
 
        public string SignatureKey
        {
            get
            {
                // We mitigate circularity problems by only actively loading attributes that pass a syntactic check
                return GetWellKnownAttributeDataStringField(data => data.AssemblySignatureKeyAttributeSetting,
                    missingValue: null, QuickAttributes.AssemblySignatureKey);
            }
        }
 
        private Version AssemblyVersionAttributeSetting
        {
            get
            {
                var defaultValue = (Version)null;
                var fieldValue = defaultValue;
 
                var data = GetSourceDecodedWellKnownAttributeData();
                if (data != null)
                {
                    fieldValue = data.AssemblyVersionAttributeSetting;
                }
 
                if (fieldValue == defaultValue)
                {
                    data = GetNetModuleDecodedWellKnownAttributeData();
                    if (data != null)
                    {
                        fieldValue = data.AssemblyVersionAttributeSetting;
                    }
                }
 
                return fieldValue;
            }
        }
 
        public override Version AssemblyVersionPattern
        {
            get
            {
                var attributeValue = AssemblyVersionAttributeSetting;
                return (object)attributeValue == null || (attributeValue.Build != ushort.MaxValue && attributeValue.Revision != ushort.MaxValue) ? null : attributeValue;
            }
        }
 
        public AssemblyHashAlgorithm HashAlgorithm
        {
            get
            {
                return AssemblyAlgorithmIdAttributeSetting ?? AssemblyHashAlgorithm.Sha1;
            }
        }
 
        internal AssemblyHashAlgorithm? AssemblyAlgorithmIdAttributeSetting
        {
            get
            {
                var fieldValue = (AssemblyHashAlgorithm?)null;
 
                var data = GetSourceDecodedWellKnownAttributeData();
                if (data != null)
                {
                    fieldValue = data.AssemblyAlgorithmIdAttributeSetting;
                }
 
                if (!fieldValue.HasValue)
                {
                    data = GetNetModuleDecodedWellKnownAttributeData();
                    if (data != null)
                    {
                        fieldValue = data.AssemblyAlgorithmIdAttributeSetting;
                    }
                }
 
                return fieldValue;
            }
        }
 
        /// <summary>
        /// This represents what the user claimed in source through the AssemblyFlagsAttribute.
        /// It may be modified as emitted due to presence or absence of the public key.
        /// </summary>
        public AssemblyFlags AssemblyFlags
        {
            get
            {
                var defaultValue = default(AssemblyFlags);
                var fieldValue = defaultValue;
 
                var data = GetSourceDecodedWellKnownAttributeData();
                if (data != null)
                {
                    fieldValue = data.AssemblyFlagsAttributeSetting;
                }
 
                data = GetNetModuleDecodedWellKnownAttributeData();
                if (data != null)
                {
                    fieldValue |= data.AssemblyFlagsAttributeSetting;
                }
 
                return fieldValue;
            }
        }
 
        private StrongNameKeys ComputeStrongNameKeys()
        {
            // when both attributes and command-line options specified, cmd line wins.
            string keyFile = _compilation.Options.CryptoKeyFile;
 
            // Public sign requires a keyfile
            if (DeclaringCompilation.Options.PublicSign)
            {
                // TODO(https://github.com/dotnet/roslyn/issues/9150):
                // Provide better error message if keys are provided by
                // the attributes. Right now we'll just fall through to the
                // "no key available" error.
 
                if (!string.IsNullOrEmpty(keyFile) && !PathUtilities.IsAbsolute(keyFile))
                {
                    // If keyFile has a relative path then there should be a diagnostic
                    // about it
                    Debug.Assert(!DeclaringCompilation.Options.Errors.IsEmpty);
                    return StrongNameKeys.None;
                }
 
                // If we're public signing, we don't need a strong name provider
                return StrongNameKeys.Create(keyFile, MessageProvider.Instance);
            }
 
            if (string.IsNullOrEmpty(keyFile))
            {
                keyFile = this.AssemblyKeyFileAttributeSetting;
 
                if ((object)keyFile == (object)WellKnownAttributeData.StringMissingValue)
                {
                    keyFile = null;
                }
            }
 
            string keyContainer = _compilation.Options.CryptoKeyContainer;
 
            if (string.IsNullOrEmpty(keyContainer))
            {
                keyContainer = this.AssemblyKeyContainerAttributeSetting;
 
                if ((object)keyContainer == (object)WellKnownAttributeData.StringMissingValue)
                {
                    keyContainer = null;
                }
            }
 
            var hasCounterSignature = !string.IsNullOrEmpty(this.SignatureKey);
            return StrongNameKeys.Create(DeclaringCompilation.Options.StrongNameProvider, keyFile, keyContainer, hasCounterSignature, MessageProvider.Instance);
        }
 
        // A collection of assemblies to which we were granted internals access by only checking matches for assembly name
        // and ignoring public key. This just acts as a set. The bool is ignored.
        private ConcurrentDictionary<AssemblySymbol, bool> _optimisticallyGrantedInternalsAccess;
 
        //EDMAURER please don't use thread local storage widely. This is hoped to be a one-off usage.
        [ThreadStatic]
        private static AssemblySymbol t_assemblyForWhichCurrentThreadIsComputingKeys;
 
        internal StrongNameKeys StrongNameKeys
        {
            get
            {
                if (_lazyStrongNameKeys == null)
                {
                    try
                    {
                        t_assemblyForWhichCurrentThreadIsComputingKeys = this;
                        Interlocked.CompareExchange(ref _lazyStrongNameKeys, ComputeStrongNameKeys(), null);
                    }
                    finally
                    {
                        t_assemblyForWhichCurrentThreadIsComputingKeys = null;
                    }
                }
 
                return _lazyStrongNameKeys;
            }
        }
 
        internal override ImmutableArray<byte> PublicKey
        {
            get { return StrongNameKeys.PublicKey; }
        }
 
        public override ImmutableArray<ModuleSymbol> Modules
        {
            get
            {
                return _modules;
            }
        }
 
        //TODO: cache
        public override ImmutableArray<Location> Locations
        {
            get
            {
                return this.Modules.SelectMany(m => m.Locations).AsImmutable();
            }
        }
 
        private void ValidateAttributeSemantics(BindingDiagnosticBag diagnostics)
        {
            //diagnostics that come from computing the public key.
            //If building a netmodule, strong name keys need not be validated. Dev11 didn't.
            if (StrongNameKeys.DiagnosticOpt != null && !_compilation.Options.OutputKind.IsNetModule())
            {
                diagnostics.Add(StrongNameKeys.DiagnosticOpt);
            }
 
            ValidateIVTPublicKeys(diagnostics);
            //diagnostics that result from IVT checks performed while in the process of computing the public key.
            CheckOptimisticIVTAccessGrants(diagnostics);
 
            DetectAttributeAndOptionConflicts(diagnostics);
 
            if (IsDelaySigned && !Identity.HasPublicKey)
            {
                diagnostics.Add(ErrorCode.WRN_DelaySignButNoKey, NoLocation.Singleton);
            }
 
            if (DeclaringCompilation.Options.PublicSign)
            {
                if (_compilation.Options.OutputKind.IsNetModule())
                {
                    diagnostics.Add(ErrorCode.ERR_PublicSignNetModule, NoLocation.Singleton);
                }
                else if (!Identity.HasPublicKey)
                {
                    diagnostics.Add(ErrorCode.ERR_PublicSignButNoKey, NoLocation.Singleton);
                }
            }
 
            // If the options and attributes applied on the compilation imply real signing,
            // but we have no private key to sign it with report an error.
            // Note that if public key is set and delay sign is off we do OSS signing, which doesn't require private key.
            // Consider: should we allow to OSS sign if the key file only contains public key?
 
            if (DeclaringCompilation.Options.OutputKind != OutputKind.NetModule &&
                DeclaringCompilation.Options.CryptoPublicKey.IsEmpty &&
                Identity.HasPublicKey &&
                !IsDelaySigned &&
                !DeclaringCompilation.Options.PublicSign &&
                !StrongNameKeys.CanSign &&
                StrongNameKeys.DiagnosticOpt == null)
            {
                // Since the container always contains both keys, the problem is that the key file didn't contain private key.
                diagnostics.Add(ErrorCode.ERR_SignButNoPrivateKey, NoLocation.Singleton, StrongNameKeys.KeyFilePath);
            }
 
            ReportDiagnosticsForSynthesizedAttributes(_compilation, diagnostics);
        }
 
        /// <summary>
        /// We're going to synthesize some well-known attributes for this assembly symbol.  However, at synthesis time, it is
        /// too late to report diagnostics or cancel the emit.  Instead, we check for use site errors on the types and members
        /// we know we'll need at synthesis time.
        /// </summary>
        /// <remarks>
        /// As in Dev10, we won't report anything if the attribute TYPES are missing (note: missing, not erroneous) because we won't
        /// synthesize anything in that case.  We'll only report diagnostics if the attribute TYPES are present and either they or 
        /// the attribute CONSTRUCTORS have errors.
        /// </remarks>
        private static void ReportDiagnosticsForSynthesizedAttributes(CSharpCompilation compilation, BindingDiagnosticBag diagnostics)
        {
            ReportDiagnosticsForUnsafeSynthesizedAttributes(compilation, diagnostics);
 
            CSharpCompilationOptions compilationOptions = compilation.Options;
            if (!compilationOptions.OutputKind.IsNetModule())
            {
                TypeSymbol compilationRelaxationsAttribute = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CompilationRelaxationsAttribute);
                Debug.Assert((object)compilationRelaxationsAttribute != null, "GetWellKnownType unexpectedly returned null");
                if (!(compilationRelaxationsAttribute is MissingMetadataTypeSymbol))
                {
                    // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if CompilationRelaxationsAttribute is found.
                    Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation,
                        WellKnownMember.System_Runtime_CompilerServices_CompilationRelaxationsAttribute__ctorInt32, diagnostics, NoLocation.Singleton);
                }
 
                TypeSymbol runtimeCompatibilityAttribute = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute);
                Debug.Assert((object)runtimeCompatibilityAttribute != null, "GetWellKnownType unexpectedly returned null");
                if (!(runtimeCompatibilityAttribute is MissingMetadataTypeSymbol))
                {
                    // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if RuntimeCompatibilityAttribute is found.
                    Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation,
                        WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__ctor, diagnostics, NoLocation.Singleton);
 
                    Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation,
                        WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__WrapNonExceptionThrows, diagnostics, NoLocation.Singleton);
                }
            }
        }
 
        /// <summary>
        /// If this compilation allows unsafe code (note: allows, not contains), then when we actually emit the assembly/module, 
        /// we're going to synthesize SecurityPermissionAttribute/UnverifiableCodeAttribute.  However, at synthesis time, it is
        /// too late to report diagnostics or cancel the emit.  Instead, we check for use site errors on the types and members
        /// we know we'll need at synthesis time.
        /// </summary>
        /// <remarks>
        /// As in Dev10, we won't report anything if the attribute TYPES are missing (note: missing, not erroneous) because we won't
        /// synthesize anything in that case.  We'll only report diagnostics if the attribute TYPES are present and either they or 
        /// the attribute CONSTRUCTORS have errors.
        /// </remarks>
        private static void ReportDiagnosticsForUnsafeSynthesizedAttributes(CSharpCompilation compilation, BindingDiagnosticBag diagnostics)
        {
            CSharpCompilationOptions compilationOptions = compilation.Options;
            if (!compilationOptions.AllowUnsafe)
            {
                return;
            }
 
            TypeSymbol unverifiableCodeAttribute = compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute);
            Debug.Assert((object)unverifiableCodeAttribute != null, "GetWellKnownType unexpectedly returned null");
            if (unverifiableCodeAttribute is MissingMetadataTypeSymbol)
            {
                return;
            }
 
            // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if
            // UnverifiableCodeAttribute is found.
            Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation,
                WellKnownMember.System_Security_UnverifiableCodeAttribute__ctor, diagnostics, NoLocation.Singleton);
 
            TypeSymbol securityPermissionAttribute = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityPermissionAttribute);
            Debug.Assert((object)securityPermissionAttribute != null, "GetWellKnownType unexpectedly returned null");
            if (securityPermissionAttribute is MissingMetadataTypeSymbol)
            {
                return;
            }
 
            TypeSymbol securityAction = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction);
            Debug.Assert((object)securityAction != null, "GetWellKnownType unexpectedly returned null");
            if (securityAction is MissingMetadataTypeSymbol)
            {
                return;
            }
 
            // As in Dev10 (see GlobalAttrBind::EmitCompilerGeneratedAttrs), we only synthesize this attribute if
            // UnverifiableCodeAttribute, SecurityAction, and SecurityPermissionAttribute are found.
            Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation,
                WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__ctor, diagnostics, NoLocation.Singleton);
 
            // Not actually an attribute, but the same logic applies.
            Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(compilation,
                WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__SkipVerification, diagnostics, NoLocation.Singleton);
        }
 
        private void ValidateIVTPublicKeys(BindingDiagnosticBag diagnostics)
        {
            EnsureAttributesAreBound();
 
            if (!this.Identity.IsStrongName)
                return;
 
            if (_lazyInternalsVisibleToMap != null)
            {
                foreach (var keys in _lazyInternalsVisibleToMap.Values)
                {
                    foreach (var oneKey in keys)
                    {
                        if (oneKey.Key.IsDefaultOrEmpty)
                        {
                            diagnostics.Add(ErrorCode.ERR_FriendAssemblySNReq, oneKey.Value.Item1, oneKey.Value.Item2);
                        }
                    }
                }
            }
        }
 
        /// <summary>
        /// True if internals are exposed at all.
        /// </summary>
        /// <remarks>
        /// Forces binding and decoding of attributes.
        /// This property shouldn't be accessed during binding as it can lead to attribute binding cycle.
        /// </remarks>
        public bool InternalsAreVisible
        {
            get
            {
                EnsureAttributesAreBound();
                return _lazyInternalsVisibleToMap != null;
            }
        }
 
        private void DetectAttributeAndOptionConflicts(BindingDiagnosticBag diagnostics)
        {
            EnsureAttributesAreBound();
 
            ThreeState assemblyDelaySignAttributeSetting = this.AssemblyDelaySignAttributeSetting;
            if (_compilation.Options.DelaySign.HasValue && (assemblyDelaySignAttributeSetting != ThreeState.Unknown) &&
                (DeclaringCompilation.Options.DelaySign.Value != (assemblyDelaySignAttributeSetting == ThreeState.True)))
            {
                diagnostics.Add(ErrorCode.WRN_CmdOptionConflictsSource, NoLocation.Singleton, "DelaySign", AttributeDescription.AssemblyDelaySignAttribute.FullName);
            }
 
            if (_compilation.Options.PublicSign && assemblyDelaySignAttributeSetting == ThreeState.True)
            {
                diagnostics.Add(ErrorCode.WRN_CmdOptionConflictsSource, NoLocation.Singleton,
                    nameof(_compilation.Options.PublicSign),
                    AttributeDescription.AssemblyDelaySignAttribute.FullName);
            }
 
            if (!String.IsNullOrEmpty(_compilation.Options.CryptoKeyContainer))
            {
                string assemblyKeyContainerAttributeSetting = this.AssemblyKeyContainerAttributeSetting;
 
                if ((object)assemblyKeyContainerAttributeSetting == (object)CommonAssemblyWellKnownAttributeData.StringMissingValue)
                {
                    if (_compilation.Options.OutputKind == OutputKind.NetModule)
                    {
                        // We need to synthesize this attribute for .NET module,
                        // touch the constructor in order to generate proper use-site diagnostics
                        Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(_compilation,
                            WellKnownMember.System_Reflection_AssemblyKeyNameAttribute__ctor,
                            diagnostics,
                            NoLocation.Singleton);
                    }
                }
                else if (String.Compare(_compilation.Options.CryptoKeyContainer, assemblyKeyContainerAttributeSetting, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    // Native compiler reports a warning in this case, notifying the user that attribute value from source is ignored,
                    // but it doesn't drop the attribute during emit. That might be fine if we produce an assembly because we actually sign it with correct
                    // key (the one from compilation options) without relying on the emitted attribute.
                    // If we are building a .NET module, things get more complicated. In particular, we don't sign the module, we emit an attribute with the key 
                    // information, which will be used to sign an assembly once the module is linked into it. If there is already an attribute like that in source,
                    // native compiler emits both of them, synthetic attribute is emitted after the one from source. Incidentally, ALink picks the last attribute
                    // for signing and things seem to work out. However, relying on the order of attributes feels fragile, especially given that Roslyn emits
                    // synthetic attributes before attributes from source. The behavior we settled on for .NET modules is that, if the attribute in source has the
                    // same value as the one in compilation options, we won't emit the synthetic attribute. If the value doesn't match, we report an error, which 
                    // is a breaking change. Bottom line, we will never produce a module or an assembly with two attributes, regardless whether values are the same
                    // or not.
                    if (_compilation.Options.OutputKind == OutputKind.NetModule)
                    {
                        diagnostics.Add(ErrorCode.ERR_CmdOptionConflictsSource, NoLocation.Singleton, AttributeDescription.AssemblyKeyNameAttribute.FullName, "CryptoKeyContainer");
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.WRN_CmdOptionConflictsSource, NoLocation.Singleton, "CryptoKeyContainer", AttributeDescription.AssemblyKeyNameAttribute.FullName);
                    }
                }
            }
 
            if (_compilation.Options.PublicSign &&
                !_compilation.Options.OutputKind.IsNetModule() &&
                (object)this.AssemblyKeyContainerAttributeSetting != (object)CommonAssemblyWellKnownAttributeData.StringMissingValue)
            {
                diagnostics.Add(ErrorCode.WRN_AttributeIgnoredWhenPublicSigning, NoLocation.Singleton, AttributeDescription.AssemblyKeyNameAttribute.FullName);
            }
 
            if (!String.IsNullOrEmpty(_compilation.Options.CryptoKeyFile))
            {
                string assemblyKeyFileAttributeSetting = this.AssemblyKeyFileAttributeSetting;
 
                if ((object)assemblyKeyFileAttributeSetting == (object)CommonAssemblyWellKnownAttributeData.StringMissingValue)
                {
                    if (_compilation.Options.OutputKind == OutputKind.NetModule)
                    {
                        // We need to synthesize this attribute for .NET module,
                        // touch the constructor in order to generate proper use-site diagnostics
                        Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(_compilation,
                            WellKnownMember.System_Reflection_AssemblyKeyFileAttribute__ctor,
                            diagnostics,
                            NoLocation.Singleton);
                    }
                }
                else if (String.Compare(_compilation.Options.CryptoKeyFile, assemblyKeyFileAttributeSetting, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    // Comment in similar section for CryptoKeyContainer is applicable here as well.
                    if (_compilation.Options.OutputKind == OutputKind.NetModule)
                    {
                        diagnostics.Add(ErrorCode.ERR_CmdOptionConflictsSource, NoLocation.Singleton, AttributeDescription.AssemblyKeyFileAttribute.FullName, "CryptoKeyFile");
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.WRN_CmdOptionConflictsSource, NoLocation.Singleton, "CryptoKeyFile", AttributeDescription.AssemblyKeyFileAttribute.FullName);
                    }
                }
            }
 
            if (_compilation.Options.PublicSign &&
                !_compilation.Options.OutputKind.IsNetModule() &&
                (object)this.AssemblyKeyFileAttributeSetting != (object)CommonAssemblyWellKnownAttributeData.StringMissingValue)
            {
                diagnostics.Add(ErrorCode.WRN_AttributeIgnoredWhenPublicSigning, NoLocation.Singleton, AttributeDescription.AssemblyKeyFileAttribute.FullName);
            }
        }
 
        internal bool IsDelaySigned
        {
            get
            {
                //commandline setting trumps attribute value. Warning assumed to be given elsewhere
                if (_compilation.Options.DelaySign.HasValue)
                {
                    return _compilation.Options.DelaySign.Value;
                }
 
                // The public sign argument should also override the attribute
                if (_compilation.Options.PublicSign)
                {
                    return false;
                }
 
                return (this.AssemblyDelaySignAttributeSetting == ThreeState.True);
            }
        }
 
        internal SourceModuleSymbol SourceModule
        {
            get { return (SourceModuleSymbol)this.Modules[0]; }
        }
 
        internal override bool RequiresCompletion
        {
            get { return true; }
        }
 
        internal override bool HasComplete(CompletionPart part)
        {
            return _state.HasComplete(part);
        }
 
#nullable enable
        internal override void ForceComplete(SourceLocation? locationOpt, Predicate<Symbol>? filter, CancellationToken cancellationToken)
        {
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var incompletePart = _state.NextIncompletePart;
                switch (incompletePart)
                {
                    case CompletionPart.Attributes:
                        EnsureAttributesAreBound();
                        break;
                    case CompletionPart.StartAttributeChecks:
                    case CompletionPart.FinishAttributeChecks:
                        if (_state.NotePartComplete(CompletionPart.StartAttributeChecks))
                        {
                            var diagnostics = BindingDiagnosticBag.GetInstance();
                            ValidateAttributeSemantics(diagnostics);
                            AddDeclarationDiagnostics(diagnostics);
                            var thisThreadCompleted = _state.NotePartComplete(CompletionPart.FinishAttributeChecks);
                            Debug.Assert(thisThreadCompleted);
                            diagnostics.Free();
                        }
                        break;
                    case CompletionPart.Module:
                        SourceModule.ForceComplete(locationOpt, filter, cancellationToken);
                        if (SourceModule.HasComplete(CompletionPart.MembersCompleted))
                        {
                            _state.NotePartComplete(CompletionPart.Module);
                            break;
                        }
                        else
                        {
                            Debug.Assert(locationOpt != null || filter != null, "If no location or filter was specified, then the module members should be completed");
                            // this is the last completion part we can handle if there is a location.
                            return;
                        }
 
                    case CompletionPart.StartValidatingAddedModules:
                    case CompletionPart.FinishValidatingAddedModules:
                        if (_state.NotePartComplete(CompletionPart.StartValidatingAddedModules))
                        {
                            ReportDiagnosticsForAddedModules();
                            var thisThreadCompleted = _state.NotePartComplete(CompletionPart.FinishValidatingAddedModules);
                            Debug.Assert(thisThreadCompleted);
                        }
                        break;
 
                    case CompletionPart.None:
                        return;
 
                    default:
                        // any other values are completion parts intended for other kinds of symbols
                        _state.NotePartComplete(CompletionPart.All & ~CompletionPart.AssemblySymbolAll);
                        break;
                }
 
                _state.SpinWaitComplete(incompletePart, cancellationToken);
            }
        }
#nullable disable
 
        private void ReportDiagnosticsForAddedModules()
        {
            var diagnostics = BindingDiagnosticBag.GetInstance();
 
            foreach (var pair in _compilation.GetBoundReferenceManager().ReferencedModuleIndexMap)
            {
                var fileRef = pair.Key as PortableExecutableReference;
 
                if ((object)fileRef != null && (object)fileRef.FilePath != null)
                {
                    string fileName = FileNameUtilities.GetFileName(fileRef.FilePath);
                    string moduleName = _modules[pair.Value].Name;
 
                    if (!string.Equals(fileName, moduleName, StringComparison.OrdinalIgnoreCase))
                    {
                        // Used to be ERR_ALinkFailed
                        diagnostics.Add(ErrorCode.ERR_NetModuleNameMismatch, NoLocation.Singleton, moduleName, fileName);
                    }
                }
            }
 
            // Alink performed these checks only when emitting an assembly.
            if (_modules.Length > 1 && !_compilation.Options.OutputKind.IsNetModule())
            {
                var assemblyMachine = this.Machine;
                bool isPlatformAgnostic = (assemblyMachine == System.Reflection.PortableExecutable.Machine.I386 && !this.Bit32Required);
                var knownModuleNames = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
 
                for (int i = 1; i < _modules.Length; i++)
                {
                    ModuleSymbol m = _modules[i];
                    if (!knownModuleNames.Add(m.Name))
                    {
                        diagnostics.Add(ErrorCode.ERR_NetModuleNameMustBeUnique, NoLocation.Singleton, m.Name);
                    }
 
                    if (!((PEModuleSymbol)m).Module.IsCOFFOnly)
                    {
                        var moduleMachine = m.Machine;
 
                        if (moduleMachine == System.Reflection.PortableExecutable.Machine.I386 && !m.Bit32Required)
                        {
                            // Other module is agnostic, this is always safe
                            ;
                        }
                        else if (isPlatformAgnostic)
                        {
                            diagnostics.Add(ErrorCode.ERR_AgnosticToMachineModule, NoLocation.Singleton, m);
                        }
                        else if (assemblyMachine != moduleMachine)
                        {
                            // Different machine types, and neither is agnostic
                            // So it is a conflict
                            diagnostics.Add(ErrorCode.ERR_ConflictingMachineModule, NoLocation.Singleton, m);
                        }
                    }
                }
 
                // Assembly main module must explicitly reference all the modules referenced by other assembly 
                // modules, i.e. all modules from transitive closure must be referenced explicitly here
                for (int i = 1; i < _modules.Length; i++)
                {
                    var m = (PEModuleSymbol)_modules[i];
 
                    try
                    {
                        foreach (var referencedModuleName in m.Module.GetReferencedManagedModulesOrThrow())
                        {
                            // Do not report error for this module twice
                            if (knownModuleNames.Add(referencedModuleName))
                            {
                                diagnostics.Add(ErrorCode.ERR_MissingNetModuleReference, NoLocation.Singleton, referencedModuleName);
                            }
                        }
                    }
                    catch (BadImageFormatException)
                    {
                        diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, m), NoLocation.Singleton);
                    }
                }
            }
 
            ReportNameCollisionDiagnosticsForAddedModules(this.GlobalNamespace, diagnostics);
            AddDeclarationDiagnostics(diagnostics);
            diagnostics.Free();
        }
 
        private void ReportNameCollisionDiagnosticsForAddedModules(NamespaceSymbol ns, BindingDiagnosticBag diagnostics)
        {
            var mergedNs = ns as MergedNamespaceSymbol;
 
            if ((object)mergedNs == null)
            {
                return;
            }
 
            ImmutableArray<NamespaceSymbol> constituent = mergedNs.ConstituentNamespaces;
 
            if (constituent.Length > 2 || (constituent.Length == 2 && constituent[0].ContainingModule.Ordinal != 0 && constituent[1].ContainingModule.Ordinal != 0))
            {
                var topLevelTypesFromModules = ArrayBuilder<NamedTypeSymbol>.GetInstance();
 
                foreach (var moduleNs in constituent)
                {
                    Debug.Assert(moduleNs.Extent.Kind == NamespaceKind.Module);
 
                    if (moduleNs.ContainingModule.Ordinal != 0)
                    {
                        topLevelTypesFromModules.AddRange(moduleNs.GetTypeMembers());
                    }
                }
 
                topLevelTypesFromModules.Sort(NameCollisionForAddedModulesTypeComparer.Singleton);
 
                bool reportedAnError = false;
 
                for (int i = 0; i < topLevelTypesFromModules.Count - 1; i++)
                {
                    NamedTypeSymbol x = topLevelTypesFromModules[i];
                    NamedTypeSymbol y = topLevelTypesFromModules[i + 1];
 
                    if (x.Arity == y.Arity && x.Name == y.Name)
                    {
                        if (!reportedAnError)
                        {
                            // Skip synthetic <Module> type which every .NET module has.
                            if (x.Arity != 0 || !x.ContainingNamespace.IsGlobalNamespace || x.Name != "<Module>")
                            {
                                diagnostics.Add(ErrorCode.ERR_DuplicateNameInNS, y.GetFirstLocationOrNone(),
                                                y.ToDisplayString(SymbolDisplayFormat.ShortFormat),
                                                y.ContainingNamespace);
                            }
 
                            reportedAnError = true;
                        }
                    }
                    else
                    {
                        reportedAnError = false;
                    }
                }
 
                topLevelTypesFromModules.Free();
 
                // Descent into child namespaces.
                foreach (Symbol member in mergedNs.GetMembers())
                {
                    if (member.Kind == SymbolKind.Namespace)
                    {
                        ReportNameCollisionDiagnosticsForAddedModules((NamespaceSymbol)member, diagnostics);
                    }
                }
            }
        }
 
        private class NameCollisionForAddedModulesTypeComparer : IComparer<NamedTypeSymbol>
        {
            public static readonly NameCollisionForAddedModulesTypeComparer Singleton = new NameCollisionForAddedModulesTypeComparer();
 
            private NameCollisionForAddedModulesTypeComparer() { }
 
            public int Compare(NamedTypeSymbol x, NamedTypeSymbol y)
            {
                int result = String.CompareOrdinal(x.Name, y.Name);
 
                if (result == 0)
                {
                    result = x.Arity - y.Arity;
 
                    if (result == 0)
                    {
                        result = x.ContainingModule.Ordinal - y.ContainingModule.Ordinal;
                    }
                }
 
                return result;
            }
        }
 
        private bool IsKnownAssemblyAttribute(CSharpAttributeData attribute)
        {
            // TODO: This list used to include AssemblyOperatingSystemAttribute and AssemblyProcessorAttribute,
            //       but it doesn't look like they are defined, cannot find them on MSDN.
            if (attribute.IsTargetAttribute(AttributeDescription.AssemblyTitleAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyDescriptionAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyConfigurationAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyCultureAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyVersionAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyCompanyAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyProductAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyInformationalVersionAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyCopyrightAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyTrademarkAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyKeyFileAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyKeyNameAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyAlgorithmIdAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyFlagsAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyDelaySignAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblyFileVersionAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.SatelliteContractVersionAttribute) ||
                attribute.IsTargetAttribute(AttributeDescription.AssemblySignatureKeyAttribute))
            {
                return true;
            }
 
            return false;
        }
 
        private void AddOmittedAttributeIndex(int index)
        {
            if (_lazyOmittedAttributeIndices == null)
            {
                Interlocked.CompareExchange(ref _lazyOmittedAttributeIndices, new ConcurrentSet<int>(), null);
            }
 
            _lazyOmittedAttributeIndices.Add(index);
        }
 
        /// <summary>
        /// Gets unique source assembly attributes that should be emitted,
        /// i.e. filters out attributes with errors and duplicate attributes.
        /// </summary>
        private HashSet<CSharpAttributeData> GetUniqueSourceAssemblyAttributes()
        {
            ImmutableArray<CSharpAttributeData> appliedSourceAttributes = this.GetSourceAttributesBag().Attributes;
 
            HashSet<CSharpAttributeData> uniqueAttributes = null;
 
            for (int i = 0; i < appliedSourceAttributes.Length; i++)
            {
                CSharpAttributeData attribute = appliedSourceAttributes[i];
                if (!attribute.HasErrors)
                {
                    if (!AddUniqueAssemblyAttribute(attribute, ref uniqueAttributes))
                    {
                        AddOmittedAttributeIndex(i);
                    }
                }
            }
 
            return uniqueAttributes;
        }
 
        private static bool AddUniqueAssemblyAttribute(CSharpAttributeData attribute, ref HashSet<CSharpAttributeData> uniqueAttributes)
        {
            Debug.Assert(!attribute.HasErrors);
 
            if (uniqueAttributes == null)
            {
                uniqueAttributes = new HashSet<CSharpAttributeData>(comparer: CommonAttributeDataComparer.Instance);
            }
 
            return uniqueAttributes.Add(attribute);
        }
 
        private bool ValidateAttributeUsageForNetModuleAttribute(CSharpAttributeData attribute, string netModuleName, BindingDiagnosticBag diagnostics, ref HashSet<CSharpAttributeData> uniqueAttributes)
        {
            Debug.Assert(!attribute.HasErrors);
 
            var attributeClass = attribute.AttributeClass;
 
            if (attributeClass.GetAttributeUsageInfo().AllowMultiple)
            {
                // Duplicate attributes are allowed, but native compiler doesn't emit duplicate attributes, i.e. attributes with same constructor and arguments.
                return AddUniqueAssemblyAttribute(attribute, ref uniqueAttributes);
            }
            else
            {
                // Duplicate attributes with same attribute type are not allowed.
                // Check if there is an existing assembly attribute with same attribute type.
                if (uniqueAttributes == null || !uniqueAttributes.Contains((a) => TypeSymbol.Equals(a.AttributeClass, attributeClass, TypeCompareKind.ConsiderEverything2)))
                {
                    // Attribute with unique attribute type, not a duplicate.
                    bool success = AddUniqueAssemblyAttribute(attribute, ref uniqueAttributes);
                    Debug.Assert(success);
                    return true;
                }
                else
                {
                    // Duplicate attribute with same attribute type, we should report an error.
 
                    // Native compiler suppresses the error for
                    // (a) Duplicate well-known assembly attributes and
                    // (b) Identical duplicates, i.e. attributes with same constructor and arguments.
 
                    // For (a), native compiler picks the last of these duplicate well-known netmodule attributes, but these can vary based on the ordering of referenced netmodules.
 
                    if (IsKnownAssemblyAttribute(attribute))
                    {
                        if (!uniqueAttributes.Contains(attribute))
                        {
                            // This attribute application will be ignored.
                            diagnostics.Add(ErrorCode.WRN_AssemblyAttributeFromModuleIsOverridden, NoLocation.Singleton, attribute.AttributeClass, netModuleName);
                        }
                    }
                    else if (AddUniqueAssemblyAttribute(attribute, ref uniqueAttributes))
                    {
                        // Error
                        diagnostics.Add(ErrorCode.ERR_DuplicateAttributeInNetModule, NoLocation.Singleton, attribute.AttributeClass.Name, netModuleName);
                    }
 
                    return false;
                }
            }
 
            // CONSIDER Handling badly targeted assembly attributes from netmodules
            //if (!badDuplicateAttribute && ((attributeUsageInfo.ValidTargets & AttributeTargets.Assembly) == 0))
            //{
            //    // Error and skip
            //    diagnostics.Add(ErrorCode.ERR_AttributeOnBadSymbolTypeInNetModule, NoLocation.Singleton, attribute.AttributeClass.Name, netModuleName, attributeUsageInfo.GetValidTargetsString());
            //    return false;
            //}
        }
 
        private ImmutableArray<CSharpAttributeData> GetNetModuleAttributes(out ImmutableArray<string> netModuleNames)
        {
            ArrayBuilder<CSharpAttributeData> moduleAssemblyAttributesBuilder = null;
            ArrayBuilder<string> netModuleNameBuilder = null;
 
            for (int i = 1; i < _modules.Length; i++)
            {
                var peModuleSymbol = (Metadata.PE.PEModuleSymbol)_modules[i];
                string netModuleName = peModuleSymbol.Name;
                foreach (var attributeData in peModuleSymbol.GetAssemblyAttributes())
                {
                    if (netModuleNameBuilder == null)
                    {
                        netModuleNameBuilder = ArrayBuilder<string>.GetInstance();
                        moduleAssemblyAttributesBuilder = ArrayBuilder<CSharpAttributeData>.GetInstance();
                    }
 
                    netModuleNameBuilder.Add(netModuleName);
                    moduleAssemblyAttributesBuilder.Add(attributeData);
                }
            }
 
            if (netModuleNameBuilder == null)
            {
                netModuleNames = ImmutableArray<string>.Empty;
                return ImmutableArray<CSharpAttributeData>.Empty;
            }
 
            netModuleNames = netModuleNameBuilder.ToImmutableAndFree();
            return moduleAssemblyAttributesBuilder.ToImmutableAndFree();
        }
 
        private WellKnownAttributeData ValidateAttributeUsageAndDecodeWellKnownAttributes(
            ImmutableArray<CSharpAttributeData> attributesFromNetModules,
            ImmutableArray<string> netModuleNames,
            BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(attributesFromNetModules.Any());
            Debug.Assert(netModuleNames.Any());
            Debug.Assert(attributesFromNetModules.Length == netModuleNames.Length);
 
            int netModuleAttributesCount = attributesFromNetModules.Length;
            int sourceAttributesCount = this.GetSourceAttributesBag().Attributes.Length;
 
            // Get unique source assembly attributes.
            HashSet<CSharpAttributeData> uniqueAttributes = GetUniqueSourceAssemblyAttributes();
 
            var arguments = new DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation>();
            arguments.AttributesCount = netModuleAttributesCount;
            arguments.Diagnostics = diagnostics;
            arguments.SymbolPart = AttributeLocation.None;
 
            // Attributes from the second added module should override attributes from the first added module, etc. 
            // Attributes from source should override attributes from added modules.
            // That is why we are iterating attributes backwards.
            for (int i = netModuleAttributesCount - 1; i >= 0; i--)
            {
                var totalIndex = i + sourceAttributesCount;
 
                CSharpAttributeData attribute = attributesFromNetModules[i];
 
                diagnostics.Add(attribute.ErrorInfo, NoLocation.Singleton);
 
                if (!attribute.HasErrors && ValidateAttributeUsageForNetModuleAttribute(attribute, netModuleNames[i], diagnostics, ref uniqueAttributes))
                {
                    arguments.Attribute = attribute;
                    arguments.Index = i;
 
                    // CONSIDER: Provide usable AttributeSyntax node for diagnostics of malformed netmodule assembly attributes
                    arguments.AttributeSyntaxOpt = null;
 
                    this.DecodeWellKnownAttribute(ref arguments, totalIndex, isFromNetModule: true);
                }
                else
                {
                    AddOmittedAttributeIndex(totalIndex);
                }
            }
 
            return arguments.HasDecodedData ? arguments.DecodedData : null;
        }
 
        private void LoadAndValidateNetModuleAttributes(ref CustomAttributesBag<CSharpAttributeData> lazyNetModuleAttributesBag)
        {
            if (_compilation.Options.OutputKind.IsNetModule())
            {
                Interlocked.CompareExchange(ref lazyNetModuleAttributesBag, CustomAttributesBag<CSharpAttributeData>.Empty, null);
            }
            else
            {
                var diagnostics = BindingDiagnosticBag.GetInstance();
 
                ImmutableArray<string> netModuleNames;
                ImmutableArray<CSharpAttributeData> attributesFromNetModules = GetNetModuleAttributes(out netModuleNames);
 
                WellKnownAttributeData wellKnownData = null;
 
                if (attributesFromNetModules.Any())
                {
                    wellKnownData = ValidateAttributeUsageAndDecodeWellKnownAttributes(attributesFromNetModules, netModuleNames, diagnostics);
                }
                else
                {
                    // Compute duplicate source assembly attributes, i.e. attributes with same constructor and arguments, that must not be emitted.
                    var unused = GetUniqueSourceAssemblyAttributes();
                }
 
                // Load type forwarders from modules
                HashSet<NamedTypeSymbol> forwardedTypes = null;
 
                // Similar to attributes, type forwarders from the second added module should override type forwarders from the first added module, etc. 
                // This affects only diagnostics.
                for (int i = _modules.Length - 1; i > 0; i--)
                {
                    var peModuleSymbol = (PEModuleSymbol)_modules[i];
 
                    foreach (NamedTypeSymbol forwarded in peModuleSymbol.GetForwardedTypes())
                    {
                        if (forwardedTypes == null)
                        {
                            if (wellKnownData == null)
                            {
                                wellKnownData = new CommonAssemblyWellKnownAttributeData();
                            }
 
                            forwardedTypes = ((CommonAssemblyWellKnownAttributeData)wellKnownData).ForwardedTypes;
                            if (forwardedTypes == null)
                            {
                                forwardedTypes = new HashSet<NamedTypeSymbol>();
                                ((CommonAssemblyWellKnownAttributeData)wellKnownData).ForwardedTypes = forwardedTypes;
                            }
                        }
 
                        if (forwardedTypes.Add(forwarded))
                        {
                            if (forwarded.IsErrorType())
                            {
                                if (!diagnostics.ReportUseSite(forwarded, NoLocation.Singleton))
                                {
                                    DiagnosticInfo info = ((ErrorTypeSymbol)forwarded).ErrorInfo;
 
                                    if ((object)info != null)
                                    {
                                        diagnostics.Add(info, NoLocation.Singleton);
                                    }
                                }
                            }
                        }
                    }
                }
 
                CustomAttributesBag<CSharpAttributeData> netModuleAttributesBag;
 
                if (wellKnownData != null || attributesFromNetModules.Any())
                {
                    netModuleAttributesBag = new CustomAttributesBag<CSharpAttributeData>();
 
                    netModuleAttributesBag.SetEarlyDecodedWellKnownAttributeData(null);
                    netModuleAttributesBag.SetDecodedWellKnownAttributeData(wellKnownData);
                    netModuleAttributesBag.SetAttributes(attributesFromNetModules);
                    if (netModuleAttributesBag.IsEmpty) netModuleAttributesBag = CustomAttributesBag<CSharpAttributeData>.Empty;
                }
                else
                {
                    netModuleAttributesBag = CustomAttributesBag<CSharpAttributeData>.Empty;
                }
 
                if (Interlocked.CompareExchange(ref lazyNetModuleAttributesBag, netModuleAttributesBag, null) == null)
                {
                    this.AddDeclarationDiagnostics(diagnostics);
                }
 
                diagnostics.Free();
 
                Debug.Assert(lazyNetModuleAttributesBag.IsSealed);
            }
        }
 
        private CommonAssemblyWellKnownAttributeData GetLimitedNetModuleDecodedWellKnownAttributeData(QuickAttributes attributeMatches)
        {
            Debug.Assert(attributeMatches is QuickAttributes.AssemblyKeyFile
                or QuickAttributes.AssemblyKeyName
                or QuickAttributes.AssemblySignatureKey);
 
            if (_compilation.Options.OutputKind.IsNetModule())
            {
                return null;
            }
 
            ImmutableArray<string> netModuleNames;
            ImmutableArray<CSharpAttributeData> attributesFromNetModules = GetNetModuleAttributes(out netModuleNames);
 
            WellKnownAttributeData wellKnownData = null;
 
            if (attributesFromNetModules.Any())
            {
                wellKnownData = limitedDecodeWellKnownAttributes(attributesFromNetModules, netModuleNames, attributeMatches);
            }
 
            return (CommonAssemblyWellKnownAttributeData)wellKnownData;
 
            // Similar to ValidateAttributeUsageAndDecodeWellKnownAttributes, but doesn't load assembly-level attributes from source
            // and only decodes 3 specific attributes.
            WellKnownAttributeData limitedDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> attributesFromNetModules,
                ImmutableArray<string> netModuleNames, QuickAttributes attributeMatches)
            {
                Debug.Assert(attributesFromNetModules.Any());
                Debug.Assert(netModuleNames.Any());
                Debug.Assert(attributesFromNetModules.Length == netModuleNames.Length);
 
                int netModuleAttributesCount = attributesFromNetModules.Length;
 
                HashSet<CSharpAttributeData> uniqueAttributes = null;
                CommonAssemblyWellKnownAttributeData result = null;
 
                // Attributes from the second added module should override attributes from the first added module, etc.
                // We don't reach here when the attribute was found in source already.
                for (int i = netModuleAttributesCount - 1; i >= 0; i--)
                {
                    CSharpAttributeData attribute = attributesFromNetModules[i];
                    if (!attribute.HasErrors && ValidateAttributeUsageForNetModuleAttribute(attribute, netModuleNames[i], BindingDiagnosticBag.Discarded, ref uniqueAttributes))
                    {
                        limitedDecodeWellKnownAttribute(attribute, attributeMatches, ref result);
                    }
                }
 
                WellKnownAttributeData.Seal(result);
                return result;
            }
 
            // Similar to DecodeWellKnownAttribute but only handles 3 specific attributes and ignores diagnostics.
            void limitedDecodeWellKnownAttribute(CSharpAttributeData attribute, QuickAttributes attributeMatches, ref CommonAssemblyWellKnownAttributeData result)
            {
                if (attributeMatches is QuickAttributes.AssemblySignatureKey &&
                    attribute.IsTargetAttribute(AttributeDescription.AssemblySignatureKeyAttribute))
                {
                    result ??= new CommonAssemblyWellKnownAttributeData();
                    result.AssemblySignatureKeyAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                }
                else if (attributeMatches is QuickAttributes.AssemblyKeyFile &&
                    attribute.IsTargetAttribute(AttributeDescription.AssemblyKeyFileAttribute))
                {
                    result ??= new CommonAssemblyWellKnownAttributeData();
                    result.AssemblyKeyFileAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                }
                else if (attributeMatches is QuickAttributes.AssemblyKeyName &&
                    attribute.IsTargetAttribute(AttributeDescription.AssemblyKeyNameAttribute))
                {
                    result ??= new CommonAssemblyWellKnownAttributeData();
                    result.AssemblyKeyContainerAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                }
            }
        }
 
        private CustomAttributesBag<CSharpAttributeData> GetNetModuleAttributesBag()
        {
            if (_lazyNetModuleAttributesBag == null)
            {
                LoadAndValidateNetModuleAttributes(ref _lazyNetModuleAttributesBag);
            }
            return _lazyNetModuleAttributesBag;
        }
 
        internal CommonAssemblyWellKnownAttributeData GetNetModuleDecodedWellKnownAttributeData()
        {
            var attributesBag = this.GetNetModuleAttributesBag();
            Debug.Assert(attributesBag.IsSealed);
            return (CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData;
        }
 
        internal ImmutableArray<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
        {
            var builder = ArrayBuilder<SyntaxList<AttributeListSyntax>>.GetInstance();
            var declarations = DeclaringCompilation.MergedRootDeclaration.Declarations;
            foreach (RootSingleNamespaceDeclaration rootNs in declarations)
            {
                if (rootNs.HasAssemblyAttributes)
                {
                    var tree = rootNs.Location.SourceTree;
                    var root = (CompilationUnitSyntax)tree.GetRoot();
                    builder.Add(root.AttributeLists);
                }
            }
            return builder.ToImmutableAndFree();
        }
 
        private void EnsureAttributesAreBound()
        {
            if ((_lazySourceAttributesBag == null || !_lazySourceAttributesBag.IsSealed) &&
                LoadAndValidateAttributes(OneOrMany.Create(GetAttributeDeclarations()), ref _lazySourceAttributesBag))
            {
                _state.NotePartComplete(CompletionPart.Attributes);
            }
        }
 
        /// <summary>
        /// Returns a bag of applied custom attributes and data decoded from well-known attributes. Returns null if there are no attributes applied on the symbol.
        /// </summary>
        /// <remarks>
        /// Forces binding and decoding of attributes.
        /// </remarks>
        private CustomAttributesBag<CSharpAttributeData> GetSourceAttributesBag()
        {
            EnsureAttributesAreBound();
            return _lazySourceAttributesBag;
        }
 
        /// <summary>
        /// Gets the attributes applied on this symbol.
        /// Returns an empty array if there are no attributes.
        /// </summary>
        /// <remarks>
        /// NOTE: This method should always be kept as a sealed override.
        /// If you want to override attribute binding logic for a sub-class, then override <see cref="GetSourceAttributesBag"/> method.
        /// </remarks>
        public sealed override ImmutableArray<CSharpAttributeData> GetAttributes()
        {
            var attributes = this.GetSourceAttributesBag().Attributes;
            var netmoduleAttributes = this.GetNetModuleAttributesBag().Attributes;
            Debug.Assert(!attributes.IsDefault);
            Debug.Assert(!netmoduleAttributes.IsDefault);
 
            if (attributes.Length > 0)
            {
                if (netmoduleAttributes.Length > 0)
                {
                    attributes = attributes.Concat(netmoduleAttributes);
                }
            }
            else
            {
                attributes = netmoduleAttributes;
            }
 
            Debug.Assert(!attributes.IsDefault);
            return attributes;
        }
 
        /// <summary>
        /// Returns true if the assembly attribute at the given index is a duplicate assembly attribute that must not be emitted.
        /// Duplicate assembly attributes are attributes that bind to the same constructor and have identical arguments.
        /// </summary>
        /// <remarks>
        /// This method must be invoked only after all the assembly attributes have been bound.
        /// </remarks>
        internal bool IsIndexOfOmittedAssemblyAttribute(int index)
        {
            Debug.Assert(_lazyOmittedAttributeIndices == null || !_lazyOmittedAttributeIndices.Any(i => i < 0 || i >= this.GetAttributes().Length));
            Debug.Assert(_lazySourceAttributesBag.IsSealed);
            Debug.Assert(_lazyNetModuleAttributesBag.IsSealed);
            Debug.Assert(index >= 0);
            Debug.Assert(index < this.GetAttributes().Length);
 
            return _lazyOmittedAttributeIndices != null && _lazyOmittedAttributeIndices.Contains(index);
        }
 
        /// <summary>
        /// Returns data decoded from source assembly attributes or null if there are none.
        /// </summary>
        /// <remarks>
        /// Forces binding and decoding of attributes.
        /// TODO: We should replace methods GetSourceDecodedWellKnownAttributeData and GetNetModuleDecodedWellKnownAttributeData with
        /// a single method GetDecodedWellKnownAttributeData, which merges DecodedWellKnownAttributeData from source and netmodule attributes.
        /// </remarks>
        internal CommonAssemblyWellKnownAttributeData GetSourceDecodedWellKnownAttributeData()
        {
            var attributesBag = _lazySourceAttributesBag;
            if (attributesBag == null || !attributesBag.IsDecodedWellKnownAttributeDataComputed)
            {
                attributesBag = this.GetSourceAttributesBag();
            }
 
            return (CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData;
        }
 
#nullable enable
        /// <remarks>
        /// This implements the same logic as <see cref="GetSourceDecodedWellKnownAttributeData()"/>
        /// but loading a smaller set of attributes if possible, to reduce circularity.
        /// </remarks>
        private CommonAssemblyWellKnownAttributeData? GetSourceDecodedWellKnownAttributeData(QuickAttributes attribute)
        {
            CustomAttributesBag<CSharpAttributeData>? attributesBag = _lazySourceAttributesBag;
            if (attributesBag?.IsDecodedWellKnownAttributeDataComputed == true)
            {
                return (CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData;
            }
 
            attributesBag = null;
            Func<AttributeSyntax, bool> attributeMatches = attribute switch
            {
                QuickAttributes.AssemblySignatureKey => isPossibleAssemblySignatureKeyAttribute,
                QuickAttributes.AssemblyKeyName => isPossibleAssemblyKeyNameAttribute,
                QuickAttributes.AssemblyKeyFile => isPossibleAssemblyKeyFileAttribute,
                _ => throw ExceptionUtilities.UnexpectedValue(attribute)
            };
 
            LoadAndValidateAttributes(OneOrMany.Create(GetAttributeDeclarations()), ref attributesBag, attributeMatchesOpt: attributeMatches);
 
            return (CommonAssemblyWellKnownAttributeData?)attributesBag?.DecodedWellKnownAttributeData;
 
            bool isPossibleAssemblySignatureKeyAttribute(AttributeSyntax node)
            {
                QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker;
                return checker.IsPossibleMatch(node, QuickAttributes.AssemblySignatureKey);
            }
 
            bool isPossibleAssemblyKeyNameAttribute(AttributeSyntax node)
            {
                QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker;
                return checker.IsPossibleMatch(node, QuickAttributes.AssemblyKeyName);
            }
 
            bool isPossibleAssemblyKeyFileAttribute(AttributeSyntax node)
            {
                QuickAttributeChecker checker = this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker;
                return checker.IsPossibleMatch(node, QuickAttributes.AssemblyKeyFile);
            }
        }
#nullable disable
 
        //Please don't use thread local storage widely. This is hoped to be the second one-off usage.
        [ThreadStatic]
        private static PooledHashSet<AttributeSyntax> t_forwardedTypesAttributesInProgress;
 
        /// <summary>
        /// This only forces binding of attributes that look like they may be forwarded types attributes (syntactically).
        /// </summary>
        internal HashSet<NamedTypeSymbol> GetForwardedTypes()
        {
            CustomAttributesBag<CSharpAttributeData> attributesBag = _lazySourceAttributesBag;
            if (attributesBag?.IsDecodedWellKnownAttributeDataComputed == true)
            {
                // Use already decoded attributes
                return ((CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData)?.ForwardedTypes;
            }
 
            var allocate = t_forwardedTypesAttributesInProgress is null;
 
            if (allocate)
            {
                t_forwardedTypesAttributesInProgress = PooledHashSet<AttributeSyntax>.GetInstance();
            }
 
            try
            {
                attributesBag = null;
                LoadAndValidateAttributes(
                    OneOrMany.Create(GetAttributeDeclarations()), ref attributesBag,
                    attributeMatchesOpt: this.IsPossibleForwardedTypesAttribute,
                    beforeAttributePartBound: BeforePossibleForwardedTypesAttributePartBound,
                    afterAttributePartBound: AfterPossibleForwardedTypesAttributePartBound);
 
                var wellKnownAttributeData = (CommonAssemblyWellKnownAttributeData)attributesBag?.DecodedWellKnownAttributeData;
                return wellKnownAttributeData?.ForwardedTypes;
            }
            finally
            {
                if (allocate)
                {
                    var tofree = t_forwardedTypesAttributesInProgress;
                    t_forwardedTypesAttributesInProgress = null;
                    tofree.Free();
                }
            }
        }
 
        private static void BeforePossibleForwardedTypesAttributePartBound(AttributeSyntax node)
        {
            bool added = t_forwardedTypesAttributesInProgress.Add(node);
            Debug.Assert(added);
        }
 
        private static void AfterPossibleForwardedTypesAttributePartBound(AttributeSyntax node)
        {
            bool removed = t_forwardedTypesAttributesInProgress.Remove(node);
            Debug.Assert(removed);
        }
 
        private bool IsPossibleForwardedTypesAttribute(AttributeSyntax node)
        {
            QuickAttributeChecker checker =
                this.DeclaringCompilation.GetBinderFactory(node.SyntaxTree).GetBinder(node).QuickAttributeChecker;
 
            if (checker.IsPossibleMatch(node, QuickAttributes.TypeForwardedTo))
            {
                if (!t_forwardedTypesAttributesInProgress.Contains(node))
                {
                    return true;
                }
 
                // It looks like we started binding this attribute and circled back to it again.
                // Let's skip it.
                ;
            }
 
            return false;
        }
 
        private static IEnumerable<Cci.SecurityAttribute> GetSecurityAttributes(CustomAttributesBag<CSharpAttributeData> attributesBag)
        {
            Debug.Assert(attributesBag.IsSealed);
 
            var wellKnownAttributeData = (CommonAssemblyWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData;
            if (wellKnownAttributeData != null)
            {
                SecurityWellKnownAttributeData securityData = wellKnownAttributeData.SecurityInformation;
                if (securityData != null)
                {
                    foreach (var securityAttribute in securityData.GetSecurityAttributes<CSharpAttributeData>(attributesBag.Attributes))
                    {
                        yield return securityAttribute;
                    }
                }
            }
        }
 
        internal IEnumerable<Cci.SecurityAttribute> GetSecurityAttributes()
        {
            // user defined security attributes:
 
            foreach (var securityAttribute in GetSecurityAttributes(this.GetSourceAttributesBag()))
            {
                yield return securityAttribute;
            }
 
            // Net module assembly security attributes:
 
            foreach (var securityAttribute in GetSecurityAttributes(this.GetNetModuleAttributesBag()))
            {
                yield return securityAttribute;
            }
 
            // synthesized security attributes:
 
            if (_compilation.Options.AllowUnsafe)
            {
                // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known types aren't available.
                if (!(_compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute) is MissingMetadataTypeSymbol) &&
                    !(_compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityPermissionAttribute) is MissingMetadataTypeSymbol))
                {
                    var securityActionType = _compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction);
                    if (!(securityActionType is MissingMetadataTypeSymbol))
                    {
                        var fieldRequestMinimum = (FieldSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Security_Permissions_SecurityAction__RequestMinimum);
 
                        // NOTE: Dev10 handles missing enum value.
                        object constantValue = (object)fieldRequestMinimum == null || fieldRequestMinimum.HasUseSiteError ? 0 : fieldRequestMinimum.ConstantValue;
                        var typedConstantRequestMinimum = new TypedConstant(securityActionType, TypedConstantKind.Enum, constantValue);
 
                        var boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
                        Debug.Assert(!boolType.HasUseSiteError,
                            "Use site errors should have been checked ahead of time (type bool).");
 
                        var typedConstantTrue = new TypedConstant(boolType, TypedConstantKind.Primitive, value: true);
 
                        var attribute = _compilation.TrySynthesizeAttribute(
                            WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__ctor,
                            ImmutableArray.Create(typedConstantRequestMinimum),
                            ImmutableArray.Create(new KeyValuePair<WellKnownMember, TypedConstant>(
                                WellKnownMember.System_Security_Permissions_SecurityPermissionAttribute__SkipVerification,
                                typedConstantTrue)));
 
                        if (attribute != null)
                        {
                            yield return new Cci.SecurityAttribute((DeclarativeSecurityAction)(int)constantValue, attribute);
                        }
                    }
                }
            }
        }
 
        internal override ImmutableArray<AssemblySymbol> GetNoPiaResolutionAssemblies()
        {
            return _modules[0].GetReferencedAssemblySymbols();
        }
 
        internal override void SetNoPiaResolutionAssemblies(ImmutableArray<AssemblySymbol> assemblies)
        {
            throw ExceptionUtilities.Unreachable();
        }
 
        internal override ImmutableArray<AssemblySymbol> GetLinkedReferencedAssemblies()
        {
            // SourceAssemblySymbol is never used directly as a reference
            // when it is or any of its references is linked.
            return default(ImmutableArray<AssemblySymbol>);
        }
 
        internal override void SetLinkedReferencedAssemblies(ImmutableArray<AssemblySymbol> assemblies)
        {
            // SourceAssemblySymbol is never used directly as a reference
            // when it is or any of its references is linked.
            throw ExceptionUtilities.Unreachable();
        }
 
        internal override bool IsLinked
        {
            get
            {
                return false;
            }
        }
 
        internal bool DeclaresTheObjectClass
        {
            get
            {
                if ((object)this.CorLibrary != (object)this)
                {
                    return false;
                }
 
                var obj = GetSpecialType(SpecialType.System_Object);
 
                return !obj.IsErrorType() && obj.DeclaredAccessibility == Accessibility.Public;
            }
        }
 
        public override bool MightContainExtensionMethods
        {
            get
            {
                // Note this method returns true until all ContainsExtensionMethods is
                // called, after which the correct value will be returned. In other words,
                // the return value may change from true to false on subsequent calls.
                if (_lazyContainsExtensionMethods.HasValue())
                {
                    return _lazyContainsExtensionMethods.Value();
                }
                return true;
            }
        }
 
        private bool HasDebuggableAttribute
        {
            get
            {
                CommonAssemblyWellKnownAttributeData assemblyData = this.GetSourceDecodedWellKnownAttributeData();
                return assemblyData != null && assemblyData.HasDebuggableAttribute;
            }
        }
 
        private bool HasReferenceAssemblyAttribute
        {
            get
            {
                CommonAssemblyWellKnownAttributeData assemblyData = this.GetSourceDecodedWellKnownAttributeData();
                return assemblyData != null && assemblyData.HasReferenceAssemblyAttribute;
            }
        }
 
        internal override bool GetGuidString(out string guidString)
        {
            guidString = GetSourceDecodedWellKnownAttributeData()?.GuidAttribute;
            return guidString != null;
        }
 
        internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder<SynthesizedAttributeData> attributes)
        {
            base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
 
            CSharpCompilationOptions options = _compilation.Options;
            bool isBuildingNetModule = options.OutputKind.IsNetModule();
            bool containsExtensionMethods = this.ContainsExtensionMethods();
 
            if (containsExtensionMethods)
            {
                // No need to check if [Extension] attribute was explicitly set since
                // we'll issue CS1112 error in those cases and won't generate IL.
                AddSynthesizedAttribute(ref attributes, _compilation.TrySynthesizeAttribute(
                    WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor));
            }
 
            // Synthesize CompilationRelaxationsAttribute only if all the following requirements are met:
            // (a) We are not building a netmodule.
            // (b) There is no applied CompilationRelaxationsAttribute assembly attribute in source.
            // (c) There is no applied CompilationRelaxationsAttribute assembly attribute for any of the added PE modules.
            // Above requirements also hold for synthesizing RuntimeCompatibilityAttribute attribute.
 
            bool emitCompilationRelaxationsAttribute = !isBuildingNetModule && !this.Modules.Any(static m => m.HasAssemblyCompilationRelaxationsAttribute);
            if (emitCompilationRelaxationsAttribute)
            {
                // Synthesize attribute: [CompilationRelaxationsAttribute(CompilationRelaxations.NoStringInterning)]
 
                // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known types aren't available.
                if (!(_compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_CompilationRelaxationsAttribute) is MissingMetadataTypeSymbol))
                {
                    var int32Type = _compilation.GetSpecialType(SpecialType.System_Int32);
                    Debug.Assert(!int32Type.HasUseSiteError,
                        "Use site errors should have been checked ahead of time (type int).");
 
                    var typedConstantNoStringInterning = new TypedConstant(int32Type, TypedConstantKind.Primitive, Cci.Constants.CompilationRelaxations_NoStringInterning);
 
                    AddSynthesizedAttribute(ref attributes, _compilation.TrySynthesizeAttribute(
                        WellKnownMember.System_Runtime_CompilerServices_CompilationRelaxationsAttribute__ctorInt32,
                        ImmutableArray.Create(typedConstantNoStringInterning)));
                }
            }
 
            bool emitRuntimeCompatibilityAttribute = !isBuildingNetModule && !this.Modules.Any(static m => m.HasAssemblyRuntimeCompatibilityAttribute);
            if (emitRuntimeCompatibilityAttribute)
            {
                // Synthesize attribute: [RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)]
 
                // NOTE: GlobalAttrBind::EmitCompilerGeneratedAttrs skips attribute if the well-known types aren't available.
                if (!(_compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute) is MissingMetadataTypeSymbol))
                {
                    var boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
                    Debug.Assert(!boolType.HasUseSiteError, "Use site errors should have been checked ahead of time (type bool).");
 
                    var typedConstantTrue = new TypedConstant(boolType, TypedConstantKind.Primitive, value: true);
 
                    AddSynthesizedAttribute(ref attributes, _compilation.TrySynthesizeAttribute(
                        WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__ctor,
                        ImmutableArray<TypedConstant>.Empty,
                        ImmutableArray.Create(new KeyValuePair<WellKnownMember, TypedConstant>(
                            WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__WrapNonExceptionThrows,
                            typedConstantTrue))));
                }
            }
 
            // Synthesize DebuggableAttribute only if all the following requirements are met:
            // (a) We are not building a netmodule.
            // (b) We are emitting debug information (full or pdbonly).
            // (c) There is no applied DebuggableAttribute assembly attribute in source.
 
            // CONSIDER: Native VB compiler and Roslyn VB compiler also have an additional requirement: There is no applied DebuggableAttribute *module* attribute in source.
            // CONSIDER: Should we check for module DebuggableAttribute?
            if (!isBuildingNetModule && !this.HasDebuggableAttribute)
            {
                AddSynthesizedAttribute(ref attributes, _compilation.SynthesizeDebuggableAttribute());
            }
 
            if (_compilation.Options.OutputKind == OutputKind.NetModule)
            {
                // If the attribute is applied in source, do not add synthetic one.
                // If its value is different from the supplied through options, an error should have been reported by now.
 
                if (!string.IsNullOrEmpty(_compilation.Options.CryptoKeyContainer) &&
                    (object)AssemblyKeyContainerAttributeSetting == (object)CommonAssemblyWellKnownAttributeData.StringMissingValue)
                {
                    var stringType = _compilation.GetSpecialType(SpecialType.System_String);
                    Debug.Assert(!stringType.HasUseSiteError, "Use site errors should have been checked ahead of time (type string).");
 
                    var typedConstant = new TypedConstant(stringType, TypedConstantKind.Primitive, _compilation.Options.CryptoKeyContainer);
                    AddSynthesizedAttribute(ref attributes, _compilation.TrySynthesizeAttribute(WellKnownMember.System_Reflection_AssemblyKeyNameAttribute__ctor, ImmutableArray.Create(typedConstant)));
                }
 
                if (!String.IsNullOrEmpty(_compilation.Options.CryptoKeyFile) &&
                    (object)AssemblyKeyFileAttributeSetting == (object)CommonAssemblyWellKnownAttributeData.StringMissingValue)
                {
                    var stringType = _compilation.GetSpecialType(SpecialType.System_String);
                    Debug.Assert(!stringType.HasUseSiteError, "Use site errors should have been checked ahead of time (type string).");
 
                    var typedConstant = new TypedConstant(stringType, TypedConstantKind.Primitive, _compilation.Options.CryptoKeyFile);
                    AddSynthesizedAttribute(ref attributes, _compilation.TrySynthesizeAttribute(WellKnownMember.System_Reflection_AssemblyKeyFileAttribute__ctor, ImmutableArray.Create(typedConstant)));
                }
            }
        }
 
        /// <summary>
        /// Returns true if and only if at least one type within the assembly contains
        /// extension methods. Note, this method is expensive since it potentially
        /// inspects all types within the assembly. The expectation is that this method is
        /// only called at emit time, when all types have been or will be traversed anyway.
        /// </summary>
        private bool ContainsExtensionMethods()
        {
            if (!_lazyContainsExtensionMethods.HasValue())
            {
                _lazyContainsExtensionMethods = ContainsExtensionMethods(_modules).ToThreeState();
            }
 
            return _lazyContainsExtensionMethods.Value();
        }
 
        private static bool ContainsExtensionMethods(ImmutableArray<ModuleSymbol> modules)
        {
            foreach (var module in modules)
            {
                if (ContainsExtensionMethods(module.GlobalNamespace))
                {
                    return true;
                }
            }
            return false;
        }
 
        private static bool ContainsExtensionMethods(NamespaceSymbol ns)
        {
            foreach (var member in ns.GetMembersUnordered())
            {
                switch (member.Kind)
                {
                    case SymbolKind.Namespace:
                        if (ContainsExtensionMethods((NamespaceSymbol)member))
                        {
                            return true;
                        }
                        break;
                    case SymbolKind.NamedType:
                        if (((NamedTypeSymbol)member).MightContainExtensionMethods)
                        {
                            return true;
                        }
                        break;
                    default:
                        throw ExceptionUtilities.UnexpectedValue(member.Kind);
                }
            }
            return false;
        }
 
        //Once the computation of the AssemblyIdentity is complete, check whether
        //any of the IVT access grants that were optimistically made during AssemblyIdentity computation
        //are in fact invalid now that the full identity is known.
        private void CheckOptimisticIVTAccessGrants(BindingDiagnosticBag bag)
        {
            ConcurrentDictionary<AssemblySymbol, bool> haveGrantedAssemblies = _optimisticallyGrantedInternalsAccess;
 
            if (haveGrantedAssemblies != null)
            {
                foreach (var otherAssembly in haveGrantedAssemblies.Keys)
                {
                    IVTConclusion conclusion = MakeFinalIVTDetermination(otherAssembly);
 
                    Debug.Assert(conclusion != IVTConclusion.NoRelationshipClaimed);
 
                    if (conclusion == IVTConclusion.PublicKeyDoesntMatch)
                        bag.Add(ErrorCode.ERR_FriendRefNotEqualToThis, NoLocation.Singleton,
                                                                      otherAssembly.Identity, this.Identity);
                    else if (conclusion == IVTConclusion.OneSignedOneNot)
                        bag.Add(ErrorCode.ERR_FriendRefSigningMismatch, NoLocation.Singleton,
                                                                      otherAssembly.Identity);
                }
            }
        }
 
        internal override IEnumerable<ImmutableArray<byte>> GetInternalsVisibleToPublicKeys(string simpleName)
        {
            //EDMAURER assume that if EnsureAttributesAreBound() returns, then the internals visible to map has been populated.
            //Do not optimize by checking if m_lazyInternalsVisibleToMap is Nothing. It may be non-null yet still
            //incomplete because another thread is in the process of building it.
 
            EnsureAttributesAreBound();
 
            if (_lazyInternalsVisibleToMap == null)
                return SpecializedCollections.EmptyEnumerable<ImmutableArray<byte>>();
 
            ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, string>> result = null;
 
            _lazyInternalsVisibleToMap.TryGetValue(simpleName, out result);
 
            return (result != null) ? result.Keys : SpecializedCollections.EmptyEnumerable<ImmutableArray<byte>>();
        }
 
        internal override IEnumerable<string> GetInternalsVisibleToAssemblyNames()
        {
            EnsureAttributesAreBound();
 
            if (_lazyInternalsVisibleToMap == null)
                return SpecializedCollections.EmptyEnumerable<string>();
 
            return _lazyInternalsVisibleToMap.Keys;
        }
 
        internal override bool AreInternalsVisibleToThisAssembly(AssemblySymbol potentialGiverOfAccess)
        {
            // Ensure that optimistic IVT access is only granted to requests that originated on the thread
            //that is trying to compute the assembly identity. This gives us deterministic behavior when
            //two threads are checking IVT access but only one of them is in the process of computing identity.
 
            //as an optimization confirm that the identity has not yet been computed to avoid testing TLS
            if (_lazyStrongNameKeys == null)
            {
                var assemblyWhoseKeysAreBeingComputed = t_assemblyForWhichCurrentThreadIsComputingKeys;
                if ((object)assemblyWhoseKeysAreBeingComputed != null)
                {
                    //ThrowIfFalse(assemblyWhoseKeysAreBeingComputed Is Me);
                    if (!potentialGiverOfAccess.GetInternalsVisibleToPublicKeys(this.Name).IsEmpty())
                    {
                        if (_optimisticallyGrantedInternalsAccess == null)
                            Interlocked.CompareExchange(ref _optimisticallyGrantedInternalsAccess, new ConcurrentDictionary<AssemblySymbol, bool>(), null);
 
                        _optimisticallyGrantedInternalsAccess.TryAdd(potentialGiverOfAccess, true);
                        return true;
                    }
                    else
                        return false;
                }
            }
 
            IVTConclusion conclusion = MakeFinalIVTDetermination(potentialGiverOfAccess);
 
            return conclusion == IVTConclusion.Match || conclusion == IVTConclusion.OneSignedOneNot;
        }
 
        private AssemblyIdentity ComputeIdentity()
        {
            return new AssemblyIdentity(
                _assemblySimpleName,
                VersionHelper.GenerateVersionFromPatternAndCurrentTime(_compilation.Options.CurrentLocalTime, AssemblyVersionAttributeSetting),
                this.AssemblyCultureAttributeSetting,
                StrongNameKeys.PublicKey,
                hasPublicKey: !StrongNameKeys.PublicKey.IsDefault,
                isRetargetable: (AssemblyFlags & AssemblyFlags.Retargetable) == AssemblyFlags.Retargetable);
        }
 
        //This maps from assembly name to a set of public keys. It uses concurrent dictionaries because it is built,
        //one attribute at a time, in the callback that validates an attribute's application to a symbol. It is assumed
        //to be complete after a call to GetAttributes(). The second dictionary is acting like a set. The value element is
        //only used when the key is empty in which case it stores the location and value of the attribute string which
        //may be used to construct a diagnostic if the assembly being compiled is found to be strong named.
        private ConcurrentDictionary<string, ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, string>>> _lazyInternalsVisibleToMap;
 
        private static Location GetAssemblyAttributeLocationForDiagnostic(AttributeSyntax attributeSyntaxOpt)
        {
            return (object)attributeSyntaxOpt != null ? attributeSyntaxOpt.Location : NoLocation.Singleton;
        }
 
        private void DecodeTypeForwardedToAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments)
        {
            // this code won't be called unless we bound a well-formed, semantically correct ctor call.
            Debug.Assert(!arguments.Attribute.HasErrors);
            var diagnostics = (BindingDiagnosticBag)arguments.Diagnostics;
 
            TypeSymbol forwardedType = (TypeSymbol)arguments.Attribute.CommonConstructorArguments[0].ValueInternal;
 
            // This can happen if the argument is the null literal.
            if ((object)forwardedType == null)
            {
                diagnostics.Add(ErrorCode.ERR_InvalidFwdType, GetAssemblyAttributeLocationForDiagnostic(arguments.AttributeSyntaxOpt));
                return;
            }
 
            UseSiteInfo<AssemblySymbol> useSiteInfo = forwardedType.GetUseSiteInfo();
            if (useSiteInfo.DiagnosticInfo?.Code != (int)ErrorCode.ERR_UnexpectedUnboundGenericName &&
                diagnostics.Add(useSiteInfo, useSiteInfo.DiagnosticInfo is object ? GetAssemblyAttributeLocationForDiagnostic(arguments.AttributeSyntaxOpt) : Location.None))
            {
                return;
            }
 
            Debug.Assert(forwardedType.TypeKind != TypeKind.Error);
 
            if (forwardedType.ContainingAssembly == this)
            {
                diagnostics.Add(ErrorCode.ERR_ForwardedTypeInThisAssembly, GetAssemblyAttributeLocationForDiagnostic(arguments.AttributeSyntaxOpt), forwardedType);
                return;
            }
 
            if ((object)forwardedType.ContainingType != null)
            {
                diagnostics.Add(ErrorCode.ERR_ForwardedTypeIsNested, GetAssemblyAttributeLocationForDiagnostic(arguments.AttributeSyntaxOpt), forwardedType, forwardedType.ContainingType);
                return;
            }
 
            if (forwardedType.Kind != SymbolKind.NamedType)
            {
                // NOTE: Dev10 actually tests whether the forwarded type is an aggregate.  This would seem to
                // exclude nullable and void, but that shouldn't be an issue because they have to be defined in
                // corlib (since they are special types) and corlib can't refer to other assemblies (by definition).
 
                diagnostics.Add(ErrorCode.ERR_InvalidFwdType, GetAssemblyAttributeLocationForDiagnostic(arguments.AttributeSyntaxOpt));
                return;
            }
 
            // NOTE: There is no danger of the type being forwarded back to this assembly, because the type
            // won't even bind successfully unless we have a reference to an assembly that actually contains
            // the type.
 
            var assemblyData = arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>();
            HashSet<NamedTypeSymbol> forwardedTypes = assemblyData.ForwardedTypes;
            if (forwardedTypes == null)
            {
                forwardedTypes = new HashSet<NamedTypeSymbol>() { (NamedTypeSymbol)forwardedType };
                assemblyData.ForwardedTypes = forwardedTypes;
            }
            else if (!forwardedTypes.Add((NamedTypeSymbol)forwardedType))
            {
                // NOTE: For the purposes of reporting this error, Dev10 considers C<int> and C<char>
                // different types.  However, it will actually emit a single forwarder for C`1 (i.e.
                // we'll have to de-dup again at emit time).
                diagnostics.Add(ErrorCode.ERR_DuplicateTypeForwarder, GetAssemblyAttributeLocationForDiagnostic(arguments.AttributeSyntaxOpt), forwardedType);
            }
        }
 
        private void DecodeOneInternalsVisibleToAttribute(
            AttributeSyntax nodeOpt,
            CSharpAttributeData attrData,
            BindingDiagnosticBag diagnostics,
            int index,
            ref ConcurrentDictionary<string, ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, string>>> lazyInternalsVisibleToMap)
        {
            // this code won't be called unless we bound a well-formed, semantically correct ctor call.
            Debug.Assert(!attrData.HasErrors);
 
            string displayName = (string)attrData.CommonConstructorArguments[0].ValueInternal;
 
            if (displayName == null)
            {
                diagnostics.Add(ErrorCode.ERR_CannotPassNullForFriendAssembly, GetAssemblyAttributeLocationForDiagnostic(nodeOpt));
                return;
            }
 
            AssemblyIdentity identity;
            AssemblyIdentityParts parts;
            if (!AssemblyIdentity.TryParseDisplayName(displayName, out identity, out parts))
            {
                diagnostics.Add(ErrorCode.WRN_InvalidAssemblyName, GetAssemblyAttributeLocationForDiagnostic(nodeOpt), displayName);
                AddOmittedAttributeIndex(index);
                return;
            }
 
            // Allow public key token due to compatibility reasons, but we are not going to use its value.
            const AssemblyIdentityParts allowedParts = AssemblyIdentityParts.Name | AssemblyIdentityParts.PublicKey | AssemblyIdentityParts.PublicKeyToken;
 
            if ((parts & ~allowedParts) != 0)
            {
                diagnostics.Add(ErrorCode.ERR_FriendAssemblyBadArgs, GetAssemblyAttributeLocationForDiagnostic(nodeOpt), displayName);
                return;
            }
 
            if (lazyInternalsVisibleToMap == null)
            {
                Interlocked.CompareExchange(ref lazyInternalsVisibleToMap,
                                            new ConcurrentDictionary<string, ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, String>>>(StringComparer.OrdinalIgnoreCase), null);
            }
 
            //later, once the identity is established we confirm that if the assembly being 
            //compiled is signed all of the IVT attributes specify a key. Stash the location for that
            //in the event that a diagnostic needs to be produced.
 
            Tuple<Location, string> locationAndValue = null;
 
            // only need to store anything when there is no public key. The only reason to store
            // this stuff is for production of errors when the assembly is signed but the IVT attrib
            // doesn't contain a public key.
            if (identity.PublicKey.IsEmpty)
            {
                locationAndValue = new Tuple<Location, string>(GetAssemblyAttributeLocationForDiagnostic(nodeOpt), displayName);
            }
 
            //when two threads are attempting to update the internalsVisibleToMap one of these TryAdd()
            //calls can fail. We assume that the 'other' thread in that case will successfully add the same
            //contents eventually.
            ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, string>> keys = null;
            if (lazyInternalsVisibleToMap.TryGetValue(identity.Name, out keys))
            {
                keys.TryAdd(identity.PublicKey, locationAndValue);
            }
            else
            {
                keys = new ConcurrentDictionary<ImmutableArray<byte>, Tuple<Location, String>>();
                keys.TryAdd(identity.PublicKey, locationAndValue);
                lazyInternalsVisibleToMap.TryAdd(identity.Name, keys);
            }
        }
 
        IAttributeTargetSymbol IAttributeTargetSymbol.AttributesOwner
        {
            get { return this; }
        }
 
        AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation
        {
            get { return AttributeLocation.Assembly; }
        }
 
        AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations
        {
            get
            {
                return IsInteractive ? AttributeLocation.None : AttributeLocation.Assembly | AttributeLocation.Module;
            }
        }
 
        protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments)
        {
            DecodeWellKnownAttribute(ref arguments, arguments.Index, isFromNetModule: false);
        }
 
        private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments, int index, bool isFromNetModule)
        {
            var attribute = arguments.Attribute;
            Debug.Assert(!attribute.HasErrors);
            Debug.Assert(arguments.SymbolPart == AttributeLocation.None);
            int signature;
            var diagnostics = (BindingDiagnosticBag)arguments.Diagnostics;
 
            if (attribute.IsTargetAttribute(AttributeDescription.InternalsVisibleToAttribute))
            {
                DecodeOneInternalsVisibleToAttribute(arguments.AttributeSyntaxOpt, attribute, diagnostics, index, ref _lazyInternalsVisibleToMap);
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblySignatureKeyAttribute))
            {
                var signatureKey = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblySignatureKeyAttributeSetting = signatureKey;
 
                if (!StrongNameKeys.IsValidPublicKeyString(signatureKey))
                {
                    diagnostics.Add(ErrorCode.ERR_InvalidSignaturePublicKey, attribute.GetAttributeArgumentLocation(0));
                }
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyKeyFileAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyKeyFileAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyKeyNameAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyKeyContainerAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyDelaySignAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyDelaySignAttributeSetting = (bool)attribute.CommonConstructorArguments[0].ValueInternal ? ThreeState.True : ThreeState.False;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyVersionAttribute))
            {
                string verString = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                Version version;
                if (!VersionHelper.TryParseAssemblyVersion(verString, allowWildcard: !_compilation.IsEmitDeterministic, version: out version))
                {
                    Location attributeArgumentSyntaxLocation = attribute.GetAttributeArgumentLocation(0);
                    bool foundBadWildcard = _compilation.IsEmitDeterministic && verString?.Contains('*') == true;
                    diagnostics.Add(foundBadWildcard ? ErrorCode.ERR_InvalidVersionFormatDeterministic : ErrorCode.ERR_InvalidVersionFormat, attributeArgumentSyntaxLocation, verString ?? "<null>");
                }
 
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyVersionAttributeSetting = version;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyFileVersionAttribute))
            {
                Version dummy;
                string verString = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                if (!VersionHelper.TryParse(verString, version: out dummy))
                {
                    Location attributeArgumentSyntaxLocation = attribute.GetAttributeArgumentLocation(0);
                    diagnostics.Add(ErrorCode.WRN_InvalidVersionFormat, attributeArgumentSyntaxLocation, verString ?? "<null>");
                }
 
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyFileVersionAttributeSetting = verString;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyTitleAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyTitleAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyDescriptionAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyDescriptionAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyCultureAttribute))
            {
                var cultureString = (string)attribute.CommonConstructorArguments[0].ValueInternal;
                if (!string.IsNullOrEmpty(cultureString))
                {
                    if (_compilation.Options.OutputKind.IsApplication())
                    {
                        diagnostics.Add(ErrorCode.ERR_InvalidAssemblyCultureForExe, attribute.GetAttributeArgumentLocation(0));
                    }
                    else if (!AssemblyIdentity.IsValidCultureName(cultureString))
                    {
                        diagnostics.Add(ErrorCode.ERR_InvalidAssemblyCulture, attribute.GetAttributeArgumentLocation(0));
                        cultureString = null;
                    }
                }
 
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyCultureAttributeSetting = cultureString;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyCompanyAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyCompanyAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyProductAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyProductAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyInformationalVersionAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyInformationalVersionAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.SatelliteContractVersionAttribute))
            {
                //just check the format of this one, don't do anything else with it.
                Version dummy;
                string verString = (string)attribute.CommonConstructorArguments[0].ValueInternal;
 
                if (!VersionHelper.TryParseAssemblyVersion(verString, allowWildcard: false, version: out dummy))
                {
                    diagnostics.Add(ErrorCode.ERR_InvalidVersionFormat2, attribute.GetAttributeArgumentLocation(0), verString ?? "<null>");
                }
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyCopyrightAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyCopyrightAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.AssemblyTrademarkAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyTrademarkAttributeSetting = (string)attribute.CommonConstructorArguments[0].ValueInternal;
            }
            else if ((signature = attribute.GetTargetAttributeSignatureIndex(AttributeDescription.AssemblyFlagsAttribute)) != -1)
            {
                object value = attribute.CommonConstructorArguments[0].ValueInternal;
                AssemblyFlags nameFlags;
 
                if (signature == 0 || signature == 1)
                {
                    nameFlags = (AssemblyFlags)(AssemblyNameFlags)value;
                }
                else
                {
                    nameFlags = (AssemblyFlags)(uint)value;
                }
 
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyFlagsAttributeSetting = nameFlags;
            }
            else if (attribute.IsSecurityAttribute(_compilation))
            {
                attribute.DecodeSecurityAttribute<CommonAssemblyWellKnownAttributeData>(this, _compilation, ref arguments);
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.ClassInterfaceAttribute))
            {
                attribute.DecodeClassInterfaceAttribute(arguments.AttributeSyntaxOpt, diagnostics);
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.TypeLibVersionAttribute))
            {
                ValidateIntegralAttributeNonNegativeArguments(attribute, arguments.AttributeSyntaxOpt, diagnostics);
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.ComCompatibleVersionAttribute))
            {
                ValidateIntegralAttributeNonNegativeArguments(attribute, arguments.AttributeSyntaxOpt, diagnostics);
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.GuidAttribute))
            {
                string guidString = attribute.DecodeGuidAttribute(arguments.AttributeSyntaxOpt, diagnostics);
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().GuidAttribute = guidString;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.ImportedFromTypeLibAttribute))
            {
                if (attribute.CommonConstructorArguments.Length == 1)
                {
                    arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().HasImportedFromTypeLibAttribute = true;
                }
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.PrimaryInteropAssemblyAttribute))
            {
                if (attribute.CommonConstructorArguments.Length == 2)
                {
                    arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().HasPrimaryInteropAssemblyAttribute = true;
                }
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.CompilationRelaxationsAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().HasCompilationRelaxationsAttribute = true;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.ReferenceAssemblyAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().HasReferenceAssemblyAttribute = true;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.RuntimeCompatibilityAttribute))
            {
                bool wrapNonExceptionThrows = true;
 
                foreach (var namedArg in attribute.CommonNamedArguments)
                {
                    switch (namedArg.Key)
                    {
                        case "WrapNonExceptionThrows":
                            wrapNonExceptionThrows = namedArg.Value.DecodeValue<bool>(SpecialType.System_Boolean);
                            break;
                    }
                }
 
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().RuntimeCompatibilityWrapNonExceptionThrows = wrapNonExceptionThrows;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.DebuggableAttribute))
            {
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().HasDebuggableAttribute = true;
            }
            else if (!isFromNetModule && attribute.IsTargetAttribute(AttributeDescription.TypeForwardedToAttribute))
            {
                DecodeTypeForwardedToAttribute(ref arguments);
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.CaseSensitiveExtensionAttribute))
            {
                if ((object)arguments.AttributeSyntaxOpt != null)
                {
                    // [Extension] attribute should not be set explicitly.
                    diagnostics.Add(ErrorCode.ERR_ExplicitExtension, arguments.AttributeSyntaxOpt.Location);
                }
            }
            else if ((signature = attribute.GetTargetAttributeSignatureIndex(AttributeDescription.AssemblyAlgorithmIdAttribute)) != -1)
            {
                object value = attribute.CommonConstructorArguments[0].ValueInternal;
                AssemblyHashAlgorithm algorithmId;
 
                if (signature == 0)
                {
                    algorithmId = (AssemblyHashAlgorithm)value;
                }
                else
                {
                    algorithmId = (AssemblyHashAlgorithm)(uint)value;
                }
 
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().AssemblyAlgorithmIdAttributeSetting = algorithmId;
            }
            else if (attribute.IsTargetAttribute(AttributeDescription.ExperimentalAttribute))
            {
                var obsoleteData = attribute.DecodeExperimentalAttribute();
                arguments.GetOrCreateData<CommonAssemblyWellKnownAttributeData>().ExperimentalAttributeData = obsoleteData;
            }
        }
 
        // Checks that the integral arguments for the given well-known attribute are non-negative.
        private static void ValidateIntegralAttributeNonNegativeArguments(CSharpAttributeData attribute, AttributeSyntax nodeOpt, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(!attribute.HasErrors);
 
            int argCount = attribute.CommonConstructorArguments.Length;
            for (int i = 0; i < argCount; i++)
            {
                int arg = attribute.GetConstructorArgument<int>(i, SpecialType.System_Int32);
                if (arg < 0)
                {
                    // CS0591: Invalid value for argument to '{0}' attribute
                    diagnostics.Add(ErrorCode.ERR_InvalidAttributeArgument, attribute.GetAttributeArgumentLocation(i), (object)nodeOpt != null ? nodeOpt.GetErrorDisplayName() : "");
                }
            }
        }
 
        internal void NoteFieldAccess(FieldSymbol field, bool read, bool write)
        {
            var container = field.ContainingType as SourceMemberContainerTypeSymbol;
            if ((object)container == null)
            {
                // field is not in source.
                return;
            }
 
            container.EnsureFieldDefinitionsNoted();
 
            if (_unusedFieldWarnings.IsDefault)
            {
                if (read)
                {
                    _unreadFields.Remove(field);
                }
 
                if (write)
                {
                    bool _;
                    _unassignedFieldsMap.TryRemove(field, out _);
                }
            }
            else
            {
                // It's acceptable to run flow analysis again after the diagnostics have been computed - just
                // make sure that the nothing is different than the first time.
 
                Debug.Assert(
                     !(read && _unreadFields.Remove(field)),
                     "we are already reporting unused field warnings, there could be no more changes");
 
                Debug.Assert(
                    !(write && _unassignedFieldsMap.ContainsKey(field)),
                    "we are already reporting unused field warnings, there could be no more changes");
            }
        }
 
        internal void NoteFieldDefinition(FieldSymbol field, bool isInternal, bool isUnread)
        {
            Debug.Assert(_unusedFieldWarnings.IsDefault, "We shouldn't have computed the diagnostics if we're still noting definitions.");
 
            _unassignedFieldsMap.TryAdd(field, isInternal);
            if (isUnread)
            {
                _unreadFields.Add(field);
            }
        }
 
        internal override bool IsNetModule() => this._compilation.Options.OutputKind.IsNetModule();
 
        /// <summary>
        /// Get the warnings for unused fields.  This should only be fetched when all method bodies have been compiled.
        /// </summary>
        internal ImmutableArray<Diagnostic> GetUnusedFieldWarnings(CancellationToken cancellationToken)
        {
            if (_unusedFieldWarnings.IsDefault)
            {
                //Our maps of unread and unassigned fields won't be done until the assembly is complete.
                this.ForceComplete(locationOpt: null, filter: null, cancellationToken: cancellationToken);
 
                Debug.Assert(this.HasComplete(CompletionPart.Module),
                    "Don't consume unused field information if there are still types to be processed.");
 
                // Build this up in a local before we assign it to this.unusedFieldWarnings (so other threads
                // can see that it's not done).
                DiagnosticBag diagnostics = DiagnosticBag.GetInstance();
 
                // NOTE: two threads can come in here at the same time.  If they do, then they will
                // share the diagnostic bag.  That's alright, as long as each one processes only
                // the fields that it successfully removes from the shared map/set.  Furthermore,
                // there should be no problem with re-calling this method on the same assembly,
                // since there will be nothing left in the map/set the second time.
                bool internalsAreVisible =
                    this.InternalsAreVisible ||
                    this.IsNetModule();
 
                HashSet<FieldSymbol> handledUnreadFields = null;
 
                foreach (FieldSymbol field in _unassignedFieldsMap.Keys) // Not mutating, so no snapshot required.
                {
                    bool isInternalAccessibility;
                    bool success = _unassignedFieldsMap.TryGetValue(field, out isInternalAccessibility);
                    Debug.Assert(success, "Once CompletionPart.Module is set, no-one should be modifying the map.");
 
                    if (isInternalAccessibility && internalsAreVisible)
                    {
                        continue;
                    }
 
                    if (!field.CanBeReferencedByName)
                    {
                        continue;
                    }
 
                    var containingType = field.ContainingType as SourceNamedTypeSymbol;
                    if ((object)containingType == null)
                    {
                        continue;
                    }
 
                    if (field is TupleErrorFieldSymbol)
                    {
                        continue;
                    }
 
                    bool unread = _unreadFields.Contains(field);
                    if (unread)
                    {
                        if (handledUnreadFields == null)
                        {
                            handledUnreadFields = new HashSet<FieldSymbol>();
                        }
                        handledUnreadFields.Add(field);
                    }
 
                    if (containingType.HasStructLayoutAttribute || containingType.HasInlineArrayAttribute(out _))
                    {
                        continue;
                    }
 
                    Symbol associatedPropertyOrEvent = field.AssociatedSymbol;
                    if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event)
                    {
                        if (unread)
                        {
                            diagnostics.Add(ErrorCode.WRN_UnreferencedEvent, associatedPropertyOrEvent.GetFirstLocationOrNone(), associatedPropertyOrEvent);
                        }
                    }
                    else if (unread)
                    {
                        diagnostics.Add(ErrorCode.WRN_UnreferencedField, field.GetFirstLocationOrNone(), field);
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.WRN_UnassignedInternalField, field.GetFirstLocationOrNone(), field, DefaultValue(field.Type));
                    }
                }
 
                foreach (FieldSymbol field in _unreadFields) // Not mutating, so no snapshot required.
                {
                    if (handledUnreadFields != null && handledUnreadFields.Contains(field))
                    {
                        // Handled in the first foreach loop.
                        continue;
                    }
 
                    if (!field.CanBeReferencedByName)
                    {
                        continue;
                    }
 
                    var containingType = field.ContainingType as SourceNamedTypeSymbol;
                    if ((object)containingType != null && !containingType.HasStructLayoutAttribute && !containingType.HasInlineArrayAttribute(out _))
                    {
                        diagnostics.Add(ErrorCode.WRN_UnreferencedFieldAssg, field.GetFirstLocationOrNone(), field);
                    }
                }
 
                ImmutableInterlocked.InterlockedInitialize(ref _unusedFieldWarnings, diagnostics.ToReadOnlyAndFree());
            }
 
            Debug.Assert(!_unusedFieldWarnings.IsDefault);
            return _unusedFieldWarnings;
        }
 
        private static string DefaultValue(TypeSymbol type)
        {
            // TODO: localize these strings
            if (type.IsReferenceType) return "null";
            switch (type.SpecialType)
            {
                case SpecialType.System_Boolean:
                    return "false";
                case SpecialType.System_Byte:
                case SpecialType.System_Decimal:
                case SpecialType.System_Double:
                case SpecialType.System_Int16:
                case SpecialType.System_Int32:
                case SpecialType.System_Int64:
                case SpecialType.System_SByte:
                case SpecialType.System_Single:
                case SpecialType.System_UInt16:
                case SpecialType.System_UInt32:
                case SpecialType.System_UInt64:
                    return "0";
                default:
                    return "";
            }
        }
 
#nullable enable
 
        internal override NamedTypeSymbol? TryLookupForwardedMetadataTypeWithCycleDetection(ref MetadataTypeName emittedName, ConsList<AssemblySymbol>? visitedAssemblies)
        {
            int forcedArity = emittedName.ForcedArity;
 
            if (emittedName.UseCLSCompliantNameArityEncoding)
            {
                if (forcedArity == -1)
                {
                    forcedArity = emittedName.InferredArity;
                }
                else if (forcedArity != emittedName.InferredArity)
                {
                    return null;
                }
 
                Debug.Assert(forcedArity == emittedName.InferredArity);
            }
 
            if (_lazyForwardedTypesFromSource == null)
            {
                IDictionary<string, NamedTypeSymbol> forwardedTypesFromSource;
                // Get the TypeForwardedTo attributes with minimal binding to avoid cycle problems
                HashSet<NamedTypeSymbol> forwardedTypes = GetForwardedTypes();
 
                if (forwardedTypes != null)
                {
                    forwardedTypesFromSource = new Dictionary<string, NamedTypeSymbol>(StringOrdinalComparer.Instance);
 
                    foreach (NamedTypeSymbol forwardedType in forwardedTypes)
                    {
                        NamedTypeSymbol originalDefinition = forwardedType.OriginalDefinition;
                        Debug.Assert((object)originalDefinition.ContainingType == null, "How did a nested type get forwarded?");
 
                        string fullEmittedName = MetadataHelpers.BuildQualifiedName(originalDefinition.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat),
                                                                                    originalDefinition.MetadataName);
                        // Since we need to allow multiple constructions of the same generic type at the source
                        // level, we need to de-dup the original definitions.
                        forwardedTypesFromSource[fullEmittedName] = originalDefinition;
                    }
                }
                else
                {
                    forwardedTypesFromSource = SpecializedCollections.EmptyDictionary<string, NamedTypeSymbol>();
                }
 
                _lazyForwardedTypesFromSource = forwardedTypesFromSource;
            }
 
            NamedTypeSymbol? result;
 
            if (_lazyForwardedTypesFromSource.TryGetValue(emittedName.FullName, out result))
            {
                if ((forcedArity == -1 || result.Arity == forcedArity) &&
                    (!emittedName.UseCLSCompliantNameArityEncoding || result.Arity == 0 || result.MangleName))
                {
                    return result;
                }
            }
            else if (!_compilation.Options.OutputKind.IsNetModule())
            {
                // See if any of added modules forward the type.
 
                // Similar to attributes, type forwarders from the second added module should override type forwarders from the first added module, etc. 
                for (int i = _modules.Length - 1; i > 0; i--)
                {
                    var peModuleSymbol = (Metadata.PE.PEModuleSymbol)_modules[i];
 
                    (AssemblySymbol firstSymbol, AssemblySymbol secondSymbol) = peModuleSymbol.GetAssembliesForForwardedType(ref emittedName);
 
                    if ((object)firstSymbol != null)
                    {
                        if ((object)secondSymbol != null)
                        {
                            return CreateMultipleForwardingErrorTypeSymbol(ref emittedName, peModuleSymbol, firstSymbol, secondSymbol);
                        }
 
                        // Don't bother to check the forwarded-to assembly if we've already seen it.
                        if (visitedAssemblies != null && visitedAssemblies.Contains(firstSymbol))
                        {
                            return CreateCycleInTypeForwarderErrorTypeSymbol(ref emittedName);
                        }
                        else
                        {
                            visitedAssemblies = new ConsList<AssemblySymbol>(this, visitedAssemblies ?? ConsList<AssemblySymbol>.Empty);
                            return firstSymbol.LookupDeclaredOrForwardedTopLevelMetadataType(ref emittedName, visitedAssemblies);
                        }
                    }
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute.
        /// This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet.
        /// </summary>
        internal sealed override ObsoleteAttributeData? ObsoleteAttributeData
        {
            get
            {
                // [assembly: Experimental] may have been specified in the assembly or one of the modules
                var lazySourceAttributesBag = _lazySourceAttributesBag;
                if (lazySourceAttributesBag != null && lazySourceAttributesBag.IsDecodedWellKnownAttributeDataComputed)
                {
                    var data = (CommonAssemblyWellKnownAttributeData)lazySourceAttributesBag.DecodedWellKnownAttributeData;
                    if (data?.ExperimentalAttributeData is { } experimentalAttributeData)
                    {
                        return experimentalAttributeData;
                    }
                }
 
                var lazyNetModuleAttributesBag = _lazyNetModuleAttributesBag;
                if (lazyNetModuleAttributesBag != null && lazyNetModuleAttributesBag.IsDecodedWellKnownAttributeDataComputed)
                {
                    var data = (CommonAssemblyWellKnownAttributeData)lazyNetModuleAttributesBag.DecodedWellKnownAttributeData;
                    return data?.ExperimentalAttributeData;
                }
 
                if (GetAttributeDeclarations().IsEmpty)
                {
                    return null;
                }
 
                return ObsoleteAttributeData.Uninitialized;
            }
        }
 
#nullable disable
 
        internal override IEnumerable<NamedTypeSymbol> GetAllTopLevelForwardedTypes()
        {
            return PEModuleBuilder.GetForwardedTypes(this, builder: null);
        }
 
        public override AssemblyMetadata GetMetadata() => null;
 
        protected override ISymbol CreateISymbol()
        {
            return new PublicModel.SourceAssemblySymbol(this);
        }
    }
}