Ejemplo n.º 1
0
        /// <summary>
        /// Returns null if an assembly of an equivalent identity has not been added previously, otherwise returns the reference that added it.
        /// Two identities are considered equivalent if
        /// - both assembly names are strong (have keys) and are either equal or FX unified
        /// - both assembly names are weak (no keys) and have the same simple name.
        /// </summary>
        private MetadataReference TryAddAssembly(
            AssemblyIdentity identity,
            MetadataReference reference,
            int assemblyIndex,
            DiagnosticBag diagnostics,
            Location location,
            Dictionary <string, List <ReferencedAssemblyIdentity> > referencesBySimpleName,
            bool supersedeLowerVersions)
        {
            var referencedAssembly = new ReferencedAssemblyIdentity(identity, reference, assemblyIndex);

            List <ReferencedAssemblyIdentity> sameSimpleNameIdentities;

            if (!referencesBySimpleName.TryGetValue(identity.Name, out sameSimpleNameIdentities))
            {
                referencesBySimpleName.Add(identity.Name, new List <ReferencedAssemblyIdentity> {
                    referencedAssembly
                });
                return(null);
            }

            if (supersedeLowerVersions)
            {
                foreach (var other in sameSimpleNameIdentities)
                {
                    if (identity.Version == other.Identity.Version)
                    {
                        return(other.Reference);
                    }
                }

                // Keep all versions of the assembly and the first identity in the list the one with the highest version:
                if (sameSimpleNameIdentities[0].Identity.Version > identity.Version)
                {
                    sameSimpleNameIdentities.Add(referencedAssembly);
                }
                else
                {
                    sameSimpleNameIdentities.Add(sameSimpleNameIdentities[0]);
                    sameSimpleNameIdentities[0] = referencedAssembly;
                }

                return(null);
            }

            ReferencedAssemblyIdentity equivalent = default(ReferencedAssemblyIdentity);

            if (identity.IsStrongName)
            {
                foreach (var other in sameSimpleNameIdentities)
                {
                    // Only compare strong with strong (weak is never equivalent to strong and vice versa).
                    // In order to eliminate duplicate references we need to try to match their identities in both directions since
                    // ReferenceMatchesDefinition is not necessarily symmetric.
                    // (e.g. System.Numerics.Vectors, Version=4.1+ matches System.Numerics.Vectors, Version=4.0, but not the other way around.)
                    if (other.Identity.IsStrongName &&
                        IdentityComparer.ReferenceMatchesDefinition(identity, other.Identity) &&
                        IdentityComparer.ReferenceMatchesDefinition(other.Identity, identity))
                    {
                        equivalent = other;
                        break;
                    }
                }
            }
            else
            {
                foreach (var other in sameSimpleNameIdentities)
                {
                    // only compare weak with weak
                    if (!other.Identity.IsStrongName && WeakIdentityPropertiesEquivalent(identity, other.Identity))
                    {
                        equivalent = other;
                        break;
                    }
                }
            }

            if (equivalent.Identity == null)
            {
                sameSimpleNameIdentities.Add(referencedAssembly);
                return(null);
            }

            // equivalent found - ignore and/or report an error:

            if (identity.IsStrongName)
            {
                Debug.Assert(equivalent.Identity.IsStrongName);

                // versions might have been unified for a Framework assembly:
                if (identity != equivalent.Identity)
                {
                    // Dev12 C# reports an error
                    // Dev12 VB keeps both references in the compilation and reports an ambiguity error when a symbol is used.
                    // BREAKING CHANGE in VB: we report an error for both languages

                    // Multiple assemblies with equivalent identity have been imported: '{0}' and '{1}'. Remove one of the duplicate references.
                    MessageProvider.ReportDuplicateMetadataReferenceStrong(diagnostics, location, reference, identity, equivalent.Reference, equivalent.Identity);
                }
                // If the versions match exactly we ignore duplicates w/o reporting errors while
                // Dev12 C# reports:
                //   error CS1703: An assembly with the same identity '{0}' has already been imported. Try removing one of the duplicate references.
                // Dev12 VB reports:
                //   Fatal error BC2000 : compiler initialization failed unexpectedly: Project already has a reference to assembly System.
                //   A second reference to 'D:\Temp\System.dll' cannot be added.
            }
            else
            {
                Debug.Assert(!equivalent.Identity.IsStrongName);

                // Dev12 reports an error for all weak-named assemblies, even if the versions are the same.
                // We treat assemblies with the same name and version equal even if they don't have a strong name.
                // This change allows us to de-duplicate #r references based on identities rather than full paths,
                // and is closer to platforms that don't support strong names and consider name and version enough
                // to identify an assembly. An identity without version is considered to have version 0.0.0.0.

                if (identity != equivalent.Identity)
                {
                    MessageProvider.ReportDuplicateMetadataReferenceWeak(diagnostics, location, reference, identity, equivalent.Reference, equivalent.Identity);
                }
            }

            Debug.Assert(equivalent.Reference != null);
            return(equivalent.Reference);
        }
Ejemplo n.º 2
0
        // Returns null if an assembly of an equivalent identity has not been added previously, otherwise returns the reference that added it.
        // - Both assembly names are strong (have keys) and are either equal or FX unified
        // - Both assembly names are weak (no keys) and have the same simple name.
        private MetadataReference TryAddAssembly(AssemblyIdentity identity, MetadataReference boundReference, DiagnosticBag diagnostics, Location location,
                                                 ref Dictionary <string, List <ReferencedAssemblyIdentity> > referencesBySimpleName)
        {
            if (referencesBySimpleName == null)
            {
                referencesBySimpleName = new Dictionary <string, List <ReferencedAssemblyIdentity> >(StringComparer.OrdinalIgnoreCase);
            }

            List <ReferencedAssemblyIdentity> sameSimpleNameIdentities;
            string simpleName = identity.Name;

            if (!referencesBySimpleName.TryGetValue(simpleName, out sameSimpleNameIdentities))
            {
                referencesBySimpleName.Add(simpleName, new List <ReferencedAssemblyIdentity> {
                    new ReferencedAssemblyIdentity(identity, boundReference)
                });
                return(null);
            }

            ReferencedAssemblyIdentity equivalent = default(ReferencedAssemblyIdentity);

            if (identity.IsStrongName)
            {
                foreach (var other in sameSimpleNameIdentities)
                {
                    // only compare strong with strong (weak is never equivalent to strong and vice versa)
                    if (other.Identity.IsStrongName && IdentityComparer.ReferenceMatchesDefinition(identity, other.Identity))
                    {
                        equivalent = other;
                        break;
                    }
                }
            }
            else
            {
                foreach (var other in sameSimpleNameIdentities)
                {
                    // only compare weak with weak
                    if (!other.Identity.IsStrongName && WeakIdentityPropertiesEquivalent(identity, other.Identity))
                    {
                        equivalent = other;
                        break;
                    }
                }
            }

            if (equivalent.Identity == null)
            {
                sameSimpleNameIdentities.Add(new ReferencedAssemblyIdentity(identity, boundReference));
                return(null);
            }

            // equivalent found - ignore and/or report an error:

            if (identity.IsStrongName)
            {
                Debug.Assert(equivalent.Identity.IsStrongName);

                // versions might have been unified for a Framework assembly:
                if (identity != equivalent.Identity)
                {
                    // Dev12 C# reports an error
                    // Dev12 VB keeps both references in the compilation and reports an ambiguity error when a symbol is used.
                    // BREAKING CHANGE in VB: we report an error for both languages

                    // Multiple assemblies with equivalent identity have been imported: '{0}' and '{1}'. Remove one of the duplicate references.
                    MessageProvider.ReportDuplicateMetadataReferenceStrong(diagnostics, location, boundReference, identity, equivalent.MetadataReference, equivalent.Identity);
                }
                // If the versions match exactly we ignore duplicates w/o reporting errors while
                // Dev12 C# reports:
                //   error CS1703: An assembly with the same identity '{0}' has already been imported. Try removing one of the duplicate references.
                // Dev12 VB reports:
                //   Fatal error BC2000 : compiler initialization failed unexpectedly: Project already has a reference to assembly System.
                //   A second reference to 'D:\Temp\System.dll' cannot be added.
            }
            else
            {
                Debug.Assert(!equivalent.Identity.IsStrongName);

                // Dev12 reports an error for all weak-named assemblies, even if the versions are the same.
                // We treat assemblies with the same name and version equal even if they don't have a strong name.
                // This change allows us to de-duplicate #r references based on identities rather than full paths,
                // and is closer to platforms that don't support strong names and consider name and version enough
                // to identify an assembly. An identity without version is considered to have version 0.0.0.0.

                if (identity != equivalent.Identity)
                {
                    MessageProvider.ReportDuplicateMetadataReferenceWeak(diagnostics, location, boundReference, identity, equivalent.MetadataReference, equivalent.Identity);
                }
            }

            Debug.Assert(equivalent.MetadataReference != null);
            return(equivalent.MetadataReference);
        }