Пример #1
0
        /// <summary>
        /// For the given set of AssemblyData objects, do the following:
        ///    1) Resolve references from each assembly against other assemblies in the set.
        ///    2) Choose suitable AssemblySymbol instance for each AssemblyData object.
        ///
        /// The first element (index==0) of the assemblies array represents the assembly being built.
        /// One can think about the rest of the items in assemblies array as assembly references given to the compiler to
        ///
        /// build executable for the assembly being built.
        ///
        /// </summary>
        ///
        /// <param name="assemblies">
        /// The set of AssemblyData objects describing assemblies, for which this method should
        /// resolve references and find suitable AssemblySymbols. This array is not modified by the
        /// method.
        /// </param>
        /// <param name="hasCircularReference">
        /// True if the assembly being compiled is indirectly referenced thru some of its own references.
        /// </param>
        /// <param name="corLibraryIndex">
        /// The definition index of the COR library.
        /// </param>
        /// <returns>
        /// An array of Binding structures describing the result. It has the same amount of items as
        /// the input assemblies array, Binding structure for each input AssemblyData object resides
        /// at the same position.
        ///
        /// Each Binding structure contains the following data:
        ///
        /// -    Suitable AssemblySymbol instance for the corresponding assembly,
        ///     null reference if none is available/found. Always null for the first element, which corresponds to the assembly being built.
        ///
        /// -    Result of resolving assembly references of the corresponding assembly
        ///     against provided set of assembly definitions. Essentially, this is an array returned by
        ///     AssemblyData.BindAssemblyReferences method.
        /// </returns>
        internal BoundInputAssembly[] Bind(
            ImmutableArray <AssemblyData> assemblies,
            out bool hasCircularReference,
            out int corLibraryIndex)
        {
            Debug.Assert(!assemblies.IsDefault);

            int totalAssemblies = assemblies.Length;

            // This is the array where we store the result in.
            BoundInputAssembly[] boundInputs = new BoundInputAssembly[totalAssemblies];

            // Based on assembly identity, for each assembly,
            // bind its references against the other assemblies we have.
            for (int i = 0; i < totalAssemblies; i++)
            {
                boundInputs[i].ReferenceBinding = assemblies[i].BindAssemblyReferences(assemblies, this.IdentityComparer);
            }

            // All assembly symbols should be uninitialized at this point:
            Debug.Assert(Array.TrueForAll(boundInputs, bi => bi.AssemblySymbol == null));

            hasCircularReference = CheckCircularReference(boundInputs);

            corLibraryIndex = IndexOfCorLibrary(assemblies);

            // For each assembly, locate AssemblySymbol with similar reference resolution
            // What does similar mean?
            // Similar means:
            // 1) The same references are resolved against the assemblies that we are given.
            // 2) The same assembly is used as the COR library.

            TAssemblySymbol[] candidateInputAssemblySymbols = new TAssemblySymbol[totalAssemblies];

            // If any assembly from assemblies array refers back to assemblyBeingBuilt,
            // we know that we cannot reuse symbols for any assemblies containing NoPia
            // local types. Because we cannot reuse symbols for assembly referring back
            // to assemblyBeingBuilt.
            if (!hasCircularReference)
            {
                // Deal with assemblies containing NoPia local types.
                if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex))
                {
                    return(boundInputs);
                }
            }

            // NoPia shortcut either didn't apply or failed, go through general process
            // of matching candidates.

            ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, assemblies, corLibraryIndex);

            return(boundInputs);
        }
        /// <summary>
        /// For the given set of AssemblyData objects, do the following:
        ///    1) Resolve references from each assembly against other assemblies in the set.
        ///    2) Choose suitable AssemblySymbol instance for each AssemblyData object.
        ///
        /// The first element (index==0) of the assemblies array represents the assembly being built.
        /// One can think about the rest of the items in assemblies array as assembly references given to the compiler to
        /// build executable for the assembly being built.
        /// </summary>
        /// <param name="compilation">Compilation.</param>
        /// <param name="explicitAssemblies">
        /// An array of <see cref="AssemblyData"/> objects describing assemblies, for which this method should
        /// resolve references and find suitable AssemblySymbols. The first slot contains the assembly being built.
        /// </param>
        /// <param name="explicitModules">
        /// An array of <see cref="PEModule"/> objects describing standalone modules referenced by the compilation.
        /// </param>
        /// <param name="explicitReferences">
        /// An array of references passed to the compilation and resolved from #r directives.
        /// May contain references that were skipped during resolution (they don't have a corresponding explicit assmebly).
        /// </param>
        /// <param name="explicitReferenceMap">
        /// Maps index to <paramref name="explicitReferences"/> to an index of a resolved assembly or module in <paramref name="explicitAssemblies"/> or modules.
        /// </param>
        /// <param name="resolverOpt">
        /// Reference resolver used to look up missing assemblies.
        /// </param>
        /// <param name="supersedeLowerVersions">
        /// Hide lower versions of dependencies that have multiple versions behind an alias.
        /// </param>
        /// <param name="assemblyReferencesBySimpleName">
        /// Used to filter out assemblies that have the same strong or weak identity.
        /// Maps simple name to a list of identities. The highest version of each name is the first.
        /// </param>
        /// <param name="importOptions">
        /// Import options applied to implicitly resolved references.
        /// </param>
        /// <param name="allAssemblies">
        /// Updated array <paramref name="explicitAssemblies"/> with resolved implicitly referenced assemblies appended.
        /// </param>
        /// <param name="implicitlyResolvedReferences">
        /// Implicitly resolved references.
        /// </param>
        /// <param name="implicitlyResolvedReferenceMap">
        /// Maps indices of implicitly resolved references to the corresponding indices of resolved assemblies in <paramref name="allAssemblies"/> (explicit + implicit).
        /// </param>
        /// <param name="resolutionDiagnostics">
        /// Any diagnostics reported while resolving missing assemblies.
        /// </param>
        /// <param name="hasCircularReference">
        /// True if the assembly being compiled is indirectly referenced through some of its own references.
        /// </param>
        /// <param name="corLibraryIndex">
        /// The definition index of the COR library.
        /// </param>
        /// <return>
        /// An array of <see cref="BoundInputAssembly"/> structures describing the result. It has the same amount of items as
        /// the input assemblies array, <see cref="BoundInputAssembly"/> for each input AssemblyData object resides
        /// at the same position.
        ///
        /// Each <see cref="BoundInputAssembly"/> contains the following data:
        ///
        /// -    Suitable AssemblySymbol instance for the corresponding assembly,
        ///     null reference if none is available/found. Always null for the first element, which corresponds to the assembly being built.
        ///
        /// -    Result of resolving assembly references of the corresponding assembly
        ///     against provided set of assembly definitions. Essentially, this is an array returned by
        ///     <see cref="AssemblyData.BindAssemblyReferences(ImmutableArray{AssemblyData}, AssemblyIdentityComparer)"/> method.
        /// </return>
        protected BoundInputAssembly[] Bind(
            TCompilation compilation,
            ImmutableArray <AssemblyData> explicitAssemblies,
            ImmutableArray <PEModule> explicitModules,
            ImmutableArray <MetadataReference> explicitReferences,
            ImmutableArray <ResolvedReference> explicitReferenceMap,
            MetadataReferenceResolver resolverOpt,
            MetadataImportOptions importOptions,
            bool supersedeLowerVersions,
            [In, Out] Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName,
            out ImmutableArray <AssemblyData> allAssemblies,
            out ImmutableArray <MetadataReference> implicitlyResolvedReferences,
            out ImmutableArray <ResolvedReference> implicitlyResolvedReferenceMap,
            [In, Out] DiagnosticBag resolutionDiagnostics,
            out bool hasCircularReference,
            out int corLibraryIndex)
        {
            Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt);
            Debug.Assert(explicitReferences.Length == explicitReferenceMap.Length);

            var referenceBindings = ArrayBuilder <AssemblyReferenceBinding[]> .GetInstance();

            try
            {
                // Based on assembly identity, for each assembly,
                // bind its references against the other assemblies we have.
                for (int i = 0; i < explicitAssemblies.Length; i++)
                {
                    referenceBindings.Add(explicitAssemblies[i].BindAssemblyReferences(explicitAssemblies, IdentityComparer));
                }

                if (resolverOpt?.ResolveMissingAssemblies == true)
                {
                    ResolveAndBindMissingAssemblies(
                        compilation,
                        explicitAssemblies,
                        explicitModules,
                        explicitReferences,
                        explicitReferenceMap,
                        resolverOpt,
                        importOptions,
                        supersedeLowerVersions,
                        referenceBindings,
                        assemblyReferencesBySimpleName,
                        out allAssemblies,
                        out implicitlyResolvedReferences,
                        out implicitlyResolvedReferenceMap,
                        resolutionDiagnostics);
                }
                else
                {
                    allAssemblies = explicitAssemblies;
                    implicitlyResolvedReferences   = ImmutableArray <MetadataReference> .Empty;
                    implicitlyResolvedReferenceMap = ImmutableArray <ResolvedReference> .Empty;
                }

                // implicitly resolved missing assemblies were added to both referenceBindings and assemblies:
                Debug.Assert(referenceBindings.Count == allAssemblies.Length);

                hasCircularReference = CheckCircularReference(referenceBindings);
                corLibraryIndex      = IndexOfCorLibrary(explicitAssemblies, assemblyReferencesBySimpleName, supersedeLowerVersions);

                // For each assembly, locate AssemblySymbol with similar reference resolution
                // What does similar mean?
                // Similar means:
                // 1) The same references are resolved against the assemblies that we are given
                //   (or were found duiring implicit assembly resolution).
                // 2) The same assembly is used as the COR library.

                var boundInputs = new BoundInputAssembly[referenceBindings.Count];
                for (int i = 0; i < referenceBindings.Count; i++)
                {
                    boundInputs[i].ReferenceBinding = referenceBindings[i];
                }

                var candidateInputAssemblySymbols = new TAssemblySymbol[allAssemblies.Length];

                // If any assembly from assemblies array refers back to assemblyBeingBuilt,
                // we know that we cannot reuse symbols for any assemblies containing NoPia
                // local types. Because we cannot reuse symbols for assembly referring back
                // to assemblyBeingBuilt.
                if (!hasCircularReference)
                {
                    // Deal with assemblies containing NoPia local types.
                    if (ReuseAssemblySymbolsWithNoPiaLocalTypes(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex))
                    {
                        return(boundInputs);
                    }
                }

                // NoPia shortcut either didn't apply or failed, go through general process
                // of matching candidates.

                ReuseAssemblySymbols(boundInputs, candidateInputAssemblySymbols, allAssemblies, corLibraryIndex);

                return(boundInputs);
            }
            finally
            {
                referenceBindings.Free();
            }
        }