public ExistingReferencesResolver(
                MetadataFileReferenceResolver resolver,
                ImmutableArray<PortableExecutableReference> availableReferences,
                AssemblyIdentityComparer assemblyIdentityComparer)
            {
                Debug.Assert(!availableReferences.Any(r => r.Properties.Kind != MetadataImageKind.Assembly));

                _resolver = resolver;
                _availableReferences = availableReferences;
                _assemblyIdentityComparer = assemblyIdentityComparer;
            }
            public ExistingReferencesResolver(
                ImmutableArray<PortableExecutableReference> availableReferences,
                ImmutableArray<string> referencePaths,
                string baseDirectory,
                AssemblyIdentityComparer assemblyIdentityComparer,
                TouchedFileLogger logger)
                : base(referencePaths, baseDirectory, logger)
            {
                Debug.Assert(!availableReferences.Any(r => r.Properties.Kind != MetadataImageKind.Assembly));

                _availableReferences = availableReferences;
                _assemblyIdentityComparer = assemblyIdentityComparer;
            }
예제 #3
0
        /// <summary>
        /// Resolves metadata references stored in command line arguments and reports errors for those that can't be resolved.
        /// </summary>
        internal List <MetadataReference> ResolveMetadataReferences(
            MetadataReferenceProvider metadataProvider,
            List <DiagnosticInfo> diagnostics,
            AssemblyIdentityComparer assemblyIdentityComparer,
            TouchedFileLogger touchedFiles,
            out FileResolver referenceDirectiveResolver)
        {
            using (Logger.LogBlock(FunctionId.Common_CommandLineCompiler_ResolveMetadataReferences))
            {
                string baseDirectory = Arguments.BaseDirectory;
                ImmutableArray <string> absoluteReferencePaths = MakeAbsolute(Arguments.ReferencePaths, baseDirectory);

                FileResolver externalReferenceResolver = new FileResolver(
                    absoluteReferencePaths,
                    baseDirectory,
                    touchedFiles);

                List <MetadataReference> resolved = new List <MetadataReference>();
                ResolveMetadataReferencesFromArguments(metadataProvider, diagnostics, externalReferenceResolver, resolved);

                if (Arguments.IsInteractive)
                {
                    referenceDirectiveResolver = externalReferenceResolver;
                }
                else
                {
                    // when compiling into an assembly (csc/vbc) we only allow #r that match references given on command line:
                    referenceDirectiveResolver = new ExistingReferencesResolver(
                        resolved.Where(r => r.Properties.Kind == MetadataImageKind.Assembly).OfType <MetadataFileReference>().AsImmutable(),
                        absoluteReferencePaths,
                        baseDirectory,
                        assemblyIdentityComparer,
                        touchedFiles);
                }

                return(resolved);
            }
        }
예제 #4
0
            public override AssemblyReferenceBinding[] BindAssemblyReferences(
                ImmutableArray <AssemblyData> assemblies,
                AssemblyIdentityComparer assemblyIdentityComparer)
            {
                var boundReferences = new AssemblyReferenceBinding[_referencedAssemblies.Length];

                for (int i = 0; i < _referencedAssemblyData.Length; i++)
                {
                    Debug.Assert(ReferenceEquals(_referencedAssemblyData[i], assemblies[i + 1]));
                    boundReferences[i] = new AssemblyReferenceBinding(assemblies[i + 1].Identity, i + 1);
                }

                // resolve references coming from linked modules:
                for (int i = _referencedAssemblyData.Length; i < _referencedAssemblies.Length; i++)
                {
                    boundReferences[i] = ResolveReferencedAssembly(
                        _referencedAssemblies[i],
                        assemblies,
                        assemblyIdentityComparer,
                        okToResolveAgainstCompilationBeingCreated: false); // references from added modules shouldn't resolve against the assembly we are building.
                }

                return(boundReferences);
            }
예제 #5
0
        internal void Initialize(
            OutputKind outputKind,
            string moduleName,
            string mainTypeName,
            string scriptClassName,
            string cryptoKeyContainer,
            string cryptoKeyFile,
            bool?delaySign,
            bool optimize,
            bool checkOverflow,
            int fileAlignment,
            ulong baseAddress,
            Platform platform,
            ReportDiagnostic generalDiagnosticOption,
            int warningLevel,
            IEnumerable <KeyValuePair <string, ReportDiagnostic> > specificDiagnosticOptions,
            bool highEntropyVirtualAddressSpace,
            DebugInformationKind debugInformationKind,
            SubsystemVersion subsystemVersion,
            bool concurrentBuild,
            XmlReferenceResolver xmlReferenceResolver,
            SourceReferenceResolver sourceReferenceResolver,
            MetadataReferenceResolver metadataReferenceResolver,
            MetadataReferenceProvider metadataReferenceProvider,
            AssemblyIdentityComparer assemblyIdentityComparer,
            StrongNameProvider strongNameProvider,
            MetadataImportOptions metadataImportOptions)
        {
            this.OutputKind                     = outputKind;
            this.ModuleName                     = moduleName;
            this.MainTypeName                   = mainTypeName;
            this.ScriptClassName                = scriptClassName;
            this.CryptoKeyContainer             = cryptoKeyContainer;
            this.CryptoKeyFile                  = cryptoKeyFile;
            this.DelaySign                      = delaySign;
            this.CheckOverflow                  = checkOverflow;
            this.FileAlignment                  = fileAlignment;
            this.BaseAddress                    = baseAddress;
            this.Platform                       = platform;
            this.GeneralDiagnosticOption        = generalDiagnosticOption;
            this.WarningLevel                   = warningLevel;
            this.SpecificDiagnosticOptions      = specificDiagnosticOptions.ToImmutableDictionaryOrEmpty();
            this.HighEntropyVirtualAddressSpace = highEntropyVirtualAddressSpace;
            this.DebugInformationKind           = debugInformationKind;
            this.Optimize                       = optimize;
            this.ConcurrentBuild                = concurrentBuild;
            this.SubsystemVersion               = subsystemVersion;
            this.XmlReferenceResolver           = xmlReferenceResolver;
            this.SourceReferenceResolver        = sourceReferenceResolver;
            this.MetadataReferenceResolver      = metadataReferenceResolver;
            this.MetadataReferenceProvider      = metadataReferenceProvider;
            this.StrongNameProvider             = strongNameProvider;
            this.AssemblyIdentityComparer       = assemblyIdentityComparer ?? AssemblyIdentityComparer.Default;
            this.MetadataImportOptions          = metadataImportOptions;

            this.lazyErrors = new Lazy <ImmutableArray <Diagnostic> >(() =>
            {
                var builder = ArrayBuilder <Diagnostic> .GetInstance();
                ValidateOptions(builder);
                return(builder.ToImmutableAndFree());
            });
        }
예제 #6
0
 protected abstract CompilationOptions CommonWithAssemblyIdentityComparer(AssemblyIdentityComparer comparer);
예제 #7
0
 public CompilationOptions WithAssemblyIdentityComparer(AssemblyIdentityComparer comparer)
 {
     return(CommonWithAssemblyIdentityComparer(comparer));
 }
예제 #8
0
        internal CompilationOptions(
            OutputKind outputKind,
            bool reportSuppressedDiagnostics,
            string?moduleName,
            string?mainTypeName,
            string?scriptClassName,
            string?cryptoKeyContainer,
            string?cryptoKeyFile,
            ImmutableArray <byte> cryptoPublicKey,
            bool?delaySign,
            bool publicSign,
            OptimizationLevel optimizationLevel,
            bool checkOverflow,
            Platform platform,
            ReportDiagnostic generalDiagnosticOption,
            int warningLevel,
            ImmutableDictionary <string, ReportDiagnostic> specificDiagnosticOptions,
            bool concurrentBuild,
            bool deterministic,
            DateTime currentLocalTime,
            bool debugPlusMode,
            XmlReferenceResolver?xmlReferenceResolver,
            SourceReferenceResolver?sourceReferenceResolver,
            MetadataReferenceResolver?metadataReferenceResolver,
            AssemblyIdentityComparer assemblyIdentityComparer,
            StrongNameProvider?strongNameProvider,
            MetadataImportOptions metadataImportOptions,
            bool referencesSupersedeLowerVersions)
        {
            this.OutputKind                       = outputKind;
            this.ModuleName                       = moduleName;
            this.MainTypeName                     = mainTypeName;
            this.ScriptClassName                  = scriptClassName ?? WellKnownMemberNames.DefaultScriptClassName;
            this.CryptoKeyContainer               = cryptoKeyContainer;
            this.CryptoKeyFile                    = string.IsNullOrEmpty(cryptoKeyFile) ? null : cryptoKeyFile;
            this.CryptoPublicKey                  = cryptoPublicKey.NullToEmpty();
            this.DelaySign                        = delaySign;
            this.CheckOverflow                    = checkOverflow;
            this.Platform                         = platform;
            this.GeneralDiagnosticOption          = generalDiagnosticOption;
            this.WarningLevel                     = warningLevel;
            this.SpecificDiagnosticOptions        = specificDiagnosticOptions;
            this.ReportSuppressedDiagnostics      = reportSuppressedDiagnostics;
            this.OptimizationLevel                = optimizationLevel;
            this.ConcurrentBuild                  = concurrentBuild;
            this.Deterministic                    = deterministic;
            this.CurrentLocalTime                 = currentLocalTime;
            this.DebugPlusMode                    = debugPlusMode;
            this.XmlReferenceResolver             = xmlReferenceResolver;
            this.SourceReferenceResolver          = sourceReferenceResolver;
            this.MetadataReferenceResolver        = metadataReferenceResolver;
            this.StrongNameProvider               = strongNameProvider;
            this.AssemblyIdentityComparer         = assemblyIdentityComparer ?? AssemblyIdentityComparer.Default;
            this.MetadataImportOptions            = metadataImportOptions;
            this.ReferencesSupersedeLowerVersions = referencesSupersedeLowerVersions;
            this.PublicSign                       = publicSign;

            _lazyErrors = new Lazy <ImmutableArray <Diagnostic> >(() =>
            {
                var builder = ArrayBuilder <Diagnostic> .GetInstance();
                ValidateOptions(builder);
                return(builder.ToImmutableAndFree());
            });
        }
예제 #9
0
 /// <summary>
 /// Resolve assembly references against assemblies described by provided AssemblyData objects.
 /// In other words, match assembly identities returned by AssemblyReferences property against
 /// assemblies described by provided AssemblyData objects.
 /// </summary>
 /// <param name="assemblies">An array of AssemblyData objects to match against.</param>
 /// <param name="assemblyIdentityComparer">Used to compare assembly identities.</param>
 /// <returns>
 /// For each assembly referenced by this assembly (<see cref="AssemblyReferences"/>)
 /// a description of how it binds to one of the input assemblies.
 /// </returns>
 public abstract AssemblyReferenceBinding[] BindAssemblyReferences(ImmutableArray <AssemblyData> assemblies, AssemblyIdentityComparer assemblyIdentityComparer);
예제 #10
0
 protected abstract CompilationOptions CommonWithAssemblyIdentityComparer(AssemblyIdentityComparer comparer);
예제 #11
0
 public CompilationOptions WithAssemblyIdentityComparer(AssemblyIdentityComparer comparer)
 {
     return CommonWithAssemblyIdentityComparer(comparer);
 }
예제 #12
0
        // Expects correct arguments.
        internal CompilationOptions(
            OutputKind outputKind,
            bool reportSuppressedDiagnostics,
            string moduleName,
            string mainTypeName,
            string scriptClassName,
            string cryptoKeyContainer,
            string cryptoKeyFile,
            ImmutableArray<byte> cryptoPublicKey,
            bool? delaySign,
            OptimizationLevel optimizationLevel,
            bool checkOverflow,
            Platform platform,
            ReportDiagnostic generalDiagnosticOption,
            int warningLevel,
            ImmutableDictionary<string, ReportDiagnostic> specificDiagnosticOptions,
            bool concurrentBuild,
            bool extendedCustomDebugInformation,
            bool debugPlusMode,
            XmlReferenceResolver xmlReferenceResolver,
            SourceReferenceResolver sourceReferenceResolver,
            MetadataReferenceResolver metadataReferenceResolver,
            AssemblyIdentityComparer assemblyIdentityComparer,
            StrongNameProvider strongNameProvider,
            MetadataImportOptions metadataImportOptions)
        {
            this.OutputKind = outputKind;
            this.ModuleName = moduleName;
            this.MainTypeName = mainTypeName;
            this.ScriptClassName = scriptClassName ?? WellKnownMemberNames.DefaultScriptClassName;
            this.CryptoKeyContainer = cryptoKeyContainer;
            this.CryptoKeyFile = cryptoKeyFile;
            this.CryptoPublicKey = cryptoPublicKey.NullToEmpty();
            this.DelaySign = delaySign;
            this.CheckOverflow = checkOverflow;
            this.Platform = platform;
            this.GeneralDiagnosticOption = generalDiagnosticOption;
            this.WarningLevel = warningLevel;
            this.SpecificDiagnosticOptions = specificDiagnosticOptions;
            this.ReportSuppressedDiagnostics = reportSuppressedDiagnostics;
            this.OptimizationLevel = optimizationLevel;
            this.ConcurrentBuild = concurrentBuild;
            this.ExtendedCustomDebugInformation = extendedCustomDebugInformation;
            this.DebugPlusMode = debugPlusMode;
            this.XmlReferenceResolver = xmlReferenceResolver;
            this.SourceReferenceResolver = sourceReferenceResolver;
            this.MetadataReferenceResolver = metadataReferenceResolver;
            this.StrongNameProvider = strongNameProvider;
            this.AssemblyIdentityComparer = assemblyIdentityComparer ?? AssemblyIdentityComparer.Default;
            this.MetadataImportOptions = metadataImportOptions;

            _lazyErrors = new Lazy<ImmutableArray<Diagnostic>>(() =>
            {
                var builder = ArrayBuilder<Diagnostic>.GetInstance();
                ValidateOptions(builder);
                return builder.ToImmutableAndFree();
            });
        }
예제 #13
0
        /// <summary>
        /// Used to match AssemblyRef with AssemblyDef.
        /// </summary>
        /// <param name="definitions">Array of definition identities to match against.</param>
        /// <param name="definitionStartIndex">An index of the first definition to consider, <paramref name="definitions"/> preceding this index are ignored.</param>
        /// <param name="reference">Reference identity to resolve.</param>
        /// <param name="assemblyIdentityComparer">Assembly identity comparer.</param>
        /// <returns>
        /// Returns an index the reference is bound.
        /// </returns>
        internal static AssemblyReferenceBinding ResolveReferencedAssembly(
            AssemblyIdentity reference,
            ImmutableArray <AssemblyData> definitions,
            int definitionStartIndex,
            AssemblyIdentityComparer assemblyIdentityComparer)
        {
            // Dev11 C# compiler allows the versions to not match exactly, assuming that a newer library may be used instead of an older version.
            // For a given reference it finds a definition with the lowest version that is higher then or equal to the reference version.
            // If match.Version != reference.Version a warning is reported.

            // definition with the lowest version higher than reference version, unless exact version found
            int minHigherVersionDefinition = -1;
            int maxLowerVersionDefinition  = -1;

            // Skip assembly being built for now; it will be considered at the very end:
            bool resolveAgainstAssemblyBeingBuilt = definitionStartIndex == 0;

            definitionStartIndex = Math.Max(definitionStartIndex, 1);

            for (int i = definitionStartIndex; i < definitions.Length; i++)
            {
                AssemblyIdentity definition = definitions[i].Identity;

                switch (assemblyIdentityComparer.Compare(reference, definition))
                {
                case AssemblyIdentityComparer.ComparisonResult.NotEquivalent:
                    continue;

                case AssemblyIdentityComparer.ComparisonResult.Equivalent:
                    return(new AssemblyReferenceBinding(reference, i));

                case AssemblyIdentityComparer.ComparisonResult.EquivalentIgnoringVersion:
                    if (reference.Version < definition.Version)
                    {
                        // Refers to an older assembly than we have
                        if (minHigherVersionDefinition == -1 || definition.Version < definitions[minHigherVersionDefinition].Identity.Version)
                        {
                            minHigherVersionDefinition = i;
                        }
                    }
                    else
                    {
                        Debug.Assert(reference.Version > definition.Version);

                        // Refers to a newer assembly than we have
                        if (maxLowerVersionDefinition == -1 || definition.Version > definitions[maxLowerVersionDefinition].Identity.Version)
                        {
                            maxLowerVersionDefinition = i;
                        }
                    }

                    continue;

                default:
                    throw ExceptionUtilities.Unreachable;
                }
            }

            // we haven't found definition that matches the reference

            if (minHigherVersionDefinition != -1)
            {
                return(new AssemblyReferenceBinding(reference, minHigherVersionDefinition, versionDifference: +1));
            }

            if (maxLowerVersionDefinition != -1)
            {
                return(new AssemblyReferenceBinding(reference, maxLowerVersionDefinition, versionDifference: -1));
            }

            // Handle cases where Windows.winmd is a runtime substitute for a
            // reference to a compile-time winmd. This is for scenarios such as a
            // debugger EE which constructs a compilation from the modules of
            // the running process where Windows.winmd loaded at runtime is a
            // substitute for a collection of Windows.*.winmd compile-time references.
            if (reference.IsWindowsComponent())
            {
                for (int i = definitionStartIndex; i < definitions.Length; i++)
                {
                    if (definitions[i].Identity.IsWindowsRuntime())
                    {
                        return(new AssemblyReferenceBinding(reference, i));
                    }
                }
            }

            // In the IDE it is possible the reference we're looking for is a
            // compilation reference to a source assembly. However, if the reference
            // is of ContentType WindowsRuntime then the compilation will never
            // match since all C#/VB WindowsRuntime compilations output .winmdobjs,
            // not .winmds, and the ContentType of a .winmdobj is Default.
            // If this is the case, we want to ignore the ContentType mismatch and
            // allow the compilation to match the reference.
            if (reference.ContentType == AssemblyContentType.WindowsRuntime)
            {
                for (int i = definitionStartIndex; i < definitions.Length; i++)
                {
                    var definition        = definitions[i].Identity;
                    var sourceCompilation = definitions[i].SourceCompilation;
                    if (definition.ContentType == AssemblyContentType.Default &&
                        sourceCompilation?.Options.OutputKind == OutputKind.WindowsRuntimeMetadata &&
                        AssemblyIdentityComparer.SimpleNameComparer.Equals(reference.Name, definition.Name) &&
                        reference.Version.Equals(definition.Version) &&
                        reference.IsRetargetable == definition.IsRetargetable &&
                        AssemblyIdentityComparer.CultureComparer.Equals(reference.CultureName, definition.CultureName) &&
                        AssemblyIdentity.KeysEqual(reference, definition))
                    {
                        return(new AssemblyReferenceBinding(reference, i));
                    }
                }
            }

            // As in the native compiler (see IMPORTER::MapAssemblyRefToAid), we compare against the
            // compilation (i.e. source) assembly as a last resort.  We follow the native approach of
            // skipping the public key comparison since we have yet to compute it.
            if (resolveAgainstAssemblyBeingBuilt &&
                AssemblyIdentityComparer.SimpleNameComparer.Equals(reference.Name, definitions[0].Identity.Name))
            {
                Debug.Assert(definitions[0].Identity.PublicKeyToken.IsEmpty);
                return(new AssemblyReferenceBinding(reference, 0));
            }

            return(new AssemblyReferenceBinding(reference));
        }
예제 #14
0
 // Expects correct arguments.
 internal CompilationOptions(
     OutputKind outputKind,
     string moduleName,
     string mainTypeName,
     string scriptClassName,
     string cryptoKeyContainer,
     string cryptoKeyFile,
     bool? delaySign,
     bool optimize,
     bool checkOverflow,
     int fileAlignment,
     ulong baseAddress,
     Platform platform,
     ReportDiagnostic generalDiagnosticOption,
     int warningLevel,
     IEnumerable<KeyValuePair<string, ReportDiagnostic>> specificDiagnosticOptions,
     bool highEntropyVirtualAddressSpace,
     DebugInformationKind debugInformationKind,
     SubsystemVersion subsystemVersion,
     bool concurrentBuild,
     XmlReferenceResolver xmlReferenceResolver,
     SourceReferenceResolver sourceReferenceResolver,
     MetadataReferenceResolver metadataReferenceResolver,
     MetadataReferenceProvider metadataReferenceProvider,
     AssemblyIdentityComparer assemblyIdentityComparer,
     StrongNameProvider strongNameProvider,
     MetadataImportOptions metadataImportOptions)
 {
     Initialize(
         outputKind, moduleName, mainTypeName, scriptClassName, cryptoKeyContainer, cryptoKeyFile, delaySign, optimize, checkOverflow, fileAlignment, 
         baseAddress, platform, generalDiagnosticOption, warningLevel, specificDiagnosticOptions, highEntropyVirtualAddressSpace, debugInformationKind, 
         subsystemVersion, concurrentBuild, xmlReferenceResolver, sourceReferenceResolver, metadataReferenceResolver, metadataReferenceProvider, assemblyIdentityComparer, strongNameProvider, 
         metadataImportOptions);
 }
예제 #15
0
        /// <summary>
        /// Resolves metadata references stored in command line arguments and reports errors for those that can't be resolved.
        /// </summary>
        internal List<MetadataReference> ResolveMetadataReferences(
            MetadataFileReferenceResolver externalReferenceResolver,
            MetadataFileReferenceProvider metadataProvider,
            List<DiagnosticInfo> diagnostics,
            AssemblyIdentityComparer assemblyIdentityComparer,
            TouchedFileLogger touchedFiles,
            out MetadataFileReferenceResolver referenceDirectiveResolver)
        {
            List<MetadataReference> resolved = new List<MetadataReference>();
            Arguments.ResolveMetadataReferences(new AssemblyReferenceResolver(externalReferenceResolver, metadataProvider), diagnostics, this.MessageProvider, resolved);

            if (Arguments.IsInteractive)
            {
                referenceDirectiveResolver = externalReferenceResolver;
            }
            else
            {
                // when compiling into an assembly (csc/vbc) we only allow #r that match references given on command line:
                referenceDirectiveResolver = new ExistingReferencesResolver(
                    CreateLoggingMetadataResolver(touchedFiles),
                    resolved.Where(r => r.Properties.Kind == MetadataImageKind.Assembly).OfType<PortableExecutableReference>().AsImmutable(),
                    assemblyIdentityComparer);
            }

            return resolved;
        }
        // Expects correct arguments.
        internal CompilationOptions(
            OutputKind outputKind,
            string moduleName,
            string mainTypeName,
            string scriptClassName,
            string cryptoKeyContainer,
            string cryptoKeyFile,
            bool? delaySign,
            OptimizationLevel optimizationLevel,
            bool checkOverflow,
            int fileAlignment,
            ulong baseAddress,
            Platform platform,
            ReportDiagnostic generalDiagnosticOption,
            int warningLevel,
            ImmutableDictionary<string, ReportDiagnostic> specificDiagnosticOptions,
            bool highEntropyVirtualAddressSpace,
            SubsystemVersion subsystemVersion,
            bool concurrentBuild,
            XmlReferenceResolver xmlReferenceResolver,
            SourceReferenceResolver sourceReferenceResolver,
            MetadataReferenceResolver metadataReferenceResolver,
            MetadataReferenceProvider metadataReferenceProvider,
            AssemblyIdentityComparer assemblyIdentityComparer,
            StrongNameProvider strongNameProvider,
            MetadataImportOptions metadataImportOptions,
            ImmutableArray<string> features)
        {
            this.OutputKind = outputKind;
            this.ModuleName = moduleName;
            this.MainTypeName = mainTypeName;
            this.ScriptClassName = scriptClassName;
            this.CryptoKeyContainer = cryptoKeyContainer;
            this.CryptoKeyFile = cryptoKeyFile;
            this.DelaySign = delaySign;
            this.CheckOverflow = checkOverflow;
            this.FileAlignment = fileAlignment;
            this.BaseAddress = baseAddress;
            this.Platform = platform;
            this.GeneralDiagnosticOption = generalDiagnosticOption;
            this.WarningLevel = warningLevel;
            this.SpecificDiagnosticOptions = specificDiagnosticOptions;
            this.HighEntropyVirtualAddressSpace = highEntropyVirtualAddressSpace;
            this.OptimizationLevel = optimizationLevel;
            this.ConcurrentBuild = concurrentBuild;
            this.SubsystemVersion = subsystemVersion;
            this.XmlReferenceResolver = xmlReferenceResolver;
            this.SourceReferenceResolver = sourceReferenceResolver;
            this.MetadataReferenceResolver = metadataReferenceResolver;
            this.MetadataReferenceProvider = metadataReferenceProvider;
            this.StrongNameProvider = strongNameProvider;
            this.AssemblyIdentityComparer = assemblyIdentityComparer ?? AssemblyIdentityComparer.Default;
            this.MetadataImportOptions = metadataImportOptions;
            this.Features = features;

            this.lazyErrors = new Lazy<ImmutableArray<Diagnostic>>(() =>
            {
                var builder = ArrayBuilder<Diagnostic>.GetInstance();
                ValidateOptions(builder);
                return builder.ToImmutableAndFree();
            });
        }
        /// <summary>
        /// Used to match AssemblyRef with AssemblyDef.
        /// </summary>
        /// <param name="definitions">Array of definition identities to match against.</param>
        /// <param name="reference">Reference identity to resolve.</param>
        /// <param name="assemblyIdentityComparer">Assembly identity comparer.</param>
        /// <param name="okToResolveAgainstCompilationBeingCreated"> Is it Ok to resolve reference against the compilation we are creating?</param>
        /// <returns>
        /// Returns an index the reference is bound.
        /// </returns>
        internal static AssemblyReferenceBinding ResolveReferencedAssembly(
            AssemblyIdentity reference,
            ImmutableArray <AssemblyData> definitions,
            AssemblyIdentityComparer assemblyIdentityComparer,
            bool okToResolveAgainstCompilationBeingCreated)
        {
            // Dev11 C# compiler allows the versions to not match exactly, assuming that a newer library may be used instead of an older version.
            // For a given reference it finds a definition with the lowest version that is higher then or equal to the reference version.
            // If match.Version != reference.Version a warning is reported.

            // definition with the lowest version higher than reference version, unless exact version found
            int minHigherVersionDefinition = -1;
            int maxLowerVersionDefinition  = -1;

            // NB: Start at 1, since we checked 0 above.
            for (int i = 1; i < definitions.Length; i++)
            {
                AssemblyIdentity definition = definitions[i].Identity;

                switch (assemblyIdentityComparer.Compare(reference, definition))
                {
                case AssemblyIdentityComparer.ComparisonResult.NotEquivalent:
                    continue;

                case AssemblyIdentityComparer.ComparisonResult.Equivalent:
                    return(new AssemblyReferenceBinding(reference, i));

                case AssemblyIdentityComparer.ComparisonResult.EquivalentIgnoringVersion:
                    if (reference.Version < definition.Version)
                    {
                        // Refers to an older assembly than we have
                        if (minHigherVersionDefinition == -1 || definition.Version < definitions[minHigherVersionDefinition].Identity.Version)
                        {
                            minHigherVersionDefinition = i;
                        }
                    }
                    else
                    {
                        Debug.Assert(reference.Version > definition.Version);

                        // Refers to a newer assembly than we have
                        if (maxLowerVersionDefinition == -1 || definition.Version > definitions[maxLowerVersionDefinition].Identity.Version)
                        {
                            maxLowerVersionDefinition = i;
                        }
                    }

                    continue;
                }
            }

            // we haven't found definition that matches the reference

            if (minHigherVersionDefinition != -1)
            {
                return(new AssemblyReferenceBinding(reference, minHigherVersionDefinition, versionDifference: +1));
            }

            if (maxLowerVersionDefinition != -1)
            {
                return(new AssemblyReferenceBinding(reference, maxLowerVersionDefinition, versionDifference: -1));
            }

            // As in the native compiler (see IMPORTER::MapAssemblyRefToAid), we compare against the
            // compilation (i.e. source) assembly as a last resort.  We follow the native approach of
            // skipping the public key comparison since we have yet to compute it.
            if (okToResolveAgainstCompilationBeingCreated &&
                AssemblyIdentityComparer.SimpleNameComparer.Equals(reference.Name, definitions[0].Identity.Name))
            {
                Debug.Assert(definitions[0].Identity.PublicKeyToken.IsEmpty);
                return(new AssemblyReferenceBinding(reference, 0));
            }

            return(new AssemblyReferenceBinding(reference));
        }
예제 #18
0
        /// <summary>
        /// Resolves metadata references stored in command line arguments and reports errors for those that can't be resolved.
        /// </summary>
        internal List<MetadataReference> ResolveMetadataReferences(
            MetadataReferenceResolver externalReferenceResolver,
            MetadataReferenceProvider metadataProvider,
            List<DiagnosticInfo> diagnostics,
            AssemblyIdentityComparer assemblyIdentityComparer,
            TouchedFileLogger touchedFiles,
            out MetadataReferenceResolver referenceDirectiveResolver)
        {
            using (Logger.LogBlock(FunctionId.Common_CommandLineCompiler_ResolveMetadataReferences))
            {
                List<MetadataReference> resolved = new List<MetadataReference>();
                ResolveMetadataReferencesFromArguments(externalReferenceResolver, metadataProvider, diagnostics, resolved);

                if (Arguments.IsInteractive)
                {
                    referenceDirectiveResolver = externalReferenceResolver;
                }
                else
                {
                    // when compiling into an assembly (csc/vbc) we only allow #r that match references given on command line:
                    referenceDirectiveResolver = new ExistingReferencesResolver(
                        resolved.Where(r => r.Properties.Kind == MetadataImageKind.Assembly).OfType<MetadataFileReference>().AsImmutable(),
                        Arguments.ReferencePaths,
                        Arguments.BaseDirectory,
                        assemblyIdentityComparer,
                        touchedFiles);
                }

                return resolved;
            }
        }
        /// <summary>
        /// Used to match AssemblyRef with AssemblyDef.
        /// </summary>
        /// <param name="definitions">Array of definition identities to match against.</param>
        /// <param name="reference">Reference identity to resolve.</param>
        /// <param name="assemblyIdentityComparer">Assembly identity comparer.</param>
        /// <param name="okToResolveAgainstCompilationBeingCreated"> Is it Ok to resolve reference against the compilation we are creating?</param>
        /// <returns>
        /// Returns an index the reference is bound.
        /// </returns>
        internal static AssemblyReferenceBinding ResolveReferencedAssembly(
            AssemblyIdentity reference,
            ImmutableArray <AssemblyData> definitions,
            AssemblyIdentityComparer assemblyIdentityComparer,
            bool okToResolveAgainstCompilationBeingCreated)
        {
            // Dev11 C# compiler allows the versions to not match exactly, assuming that a newer library may be used instead of an older version.
            // For a given reference it finds a definition with the lowest version that is higher then or equal to the reference version.
            // If match.Version != reference.Version a warning is reported.

            // definition with the lowest version higher than reference version, unless exact version found
            int minHigherVersionDefinition = -1;
            int maxLowerVersionDefinition  = -1;

            // NB: Start at 1, since we checked 0 above.
            const int definitionOffset = 1;

            for (int i = definitionOffset; i < definitions.Length; i++)
            {
                AssemblyIdentity definition = definitions[i].Identity;

                switch (assemblyIdentityComparer.Compare(reference, definition))
                {
                case AssemblyIdentityComparer.ComparisonResult.NotEquivalent:
                    continue;

                case AssemblyIdentityComparer.ComparisonResult.Equivalent:
                    return(new AssemblyReferenceBinding(reference, i));

                case AssemblyIdentityComparer.ComparisonResult.EquivalentIgnoringVersion:
                    if (reference.Version < definition.Version)
                    {
                        // Refers to an older assembly than we have
                        if (minHigherVersionDefinition == -1 || definition.Version < definitions[minHigherVersionDefinition].Identity.Version)
                        {
                            minHigherVersionDefinition = i;
                        }
                    }
                    else
                    {
                        Debug.Assert(reference.Version > definition.Version);

                        // Refers to a newer assembly than we have
                        if (maxLowerVersionDefinition == -1 || definition.Version > definitions[maxLowerVersionDefinition].Identity.Version)
                        {
                            maxLowerVersionDefinition = i;
                        }
                    }

                    continue;
                }
            }

            // we haven't found definition that matches the reference

            if (minHigherVersionDefinition != -1)
            {
                return(new AssemblyReferenceBinding(reference, minHigherVersionDefinition, versionDifference: +1));
            }

            if (maxLowerVersionDefinition != -1)
            {
                return(new AssemblyReferenceBinding(reference, maxLowerVersionDefinition, versionDifference: -1));
            }

            // If the reference is a winmd, see if there a substitute winmd that is
            // sufficient. For instance, a debugger EE could construct a compilation
            // from the modules of the running process, where the winmds loaded
            // at runtime are distinct from those used when the exe was compiled.
            if (reference.ContentType == AssemblyContentType.WindowsRuntime)
            {
                var defsByName = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase);
                for (int i = definitionOffset; i < definitions.Length; i++)
                {
                    var definition = definitions[i].Identity;
                    if (definition.ContentType == AssemblyContentType.WindowsRuntime)
                    {
                        defsByName.Add(definition.Name, i);
                    }
                }

                // The name of a winmd is a containing namespace for the assembly. Use
                // the definition with the longest substring that matches the reference.
                var refName = reference.Name;
                while (true)
                {
                    int index;
                    if (defsByName.TryGetValue(refName, out index))
                    {
                        return(new AssemblyReferenceBinding(reference, index));
                    }
                    int separator = refName.LastIndexOf('.');
                    if (separator < 0)
                    {
                        break;
                    }
                    refName = refName.Substring(0, separator);
                }
            }

            // As in the native compiler (see IMPORTER::MapAssemblyRefToAid), we compare against the
            // compilation (i.e. source) assembly as a last resort.  We follow the native approach of
            // skipping the public key comparison since we have yet to compute it.
            if (okToResolveAgainstCompilationBeingCreated &&
                AssemblyIdentityComparer.SimpleNameComparer.Equals(reference.Name, definitions[0].Identity.Name))
            {
                Debug.Assert(definitions[0].Identity.PublicKeyToken.IsEmpty);
                return(new AssemblyReferenceBinding(reference, 0));
            }

            return(new AssemblyReferenceBinding(reference));
        }