Exemplo n.º 1
0
        // internal for testing
        internal ComparisonResult Compare(AssemblyIdentity reference, string referenceDisplayName, AssemblyIdentity definition, out bool unificationApplied, bool ignoreVersion)
        {
            Debug.Assert((reference != null) ^ (referenceDisplayName != null));
            unificationApplied = false;
            AssemblyIdentityParts parts;

            if (reference != null)
            {
                // fast path
                bool?eq = TriviallyEquivalent(reference, definition);
                if (eq.HasValue)
                {
                    return(eq.Value ? ComparisonResult.Equivalent : ComparisonResult.NotEquivalent);
                }

                parts = AssemblyIdentityParts.Name | AssemblyIdentityParts.Version | AssemblyIdentityParts.Culture | AssemblyIdentityParts.PublicKeyToken;
            }
            else
            {
                if (!AssemblyIdentity.TryParseDisplayName(referenceDisplayName, out reference, out parts) ||
                    reference.ContentType != definition.ContentType)
                {
                    return(ComparisonResult.NotEquivalent);
                }
            }

            Debug.Assert(reference.ContentType == definition.ContentType);

            bool isDefinitionFxAssembly;

            if (!ApplyUnificationPolicies(ref reference, ref definition, parts, out isDefinitionFxAssembly))
            {
                return(ComparisonResult.NotEquivalent);
            }

            if (ReferenceEquals(reference, definition))
            {
                return(ComparisonResult.Equivalent);
            }

            bool compareCulture        = (parts & AssemblyIdentityParts.Culture) != 0;
            bool comparePublicKeyToken = (parts & AssemblyIdentityParts.PublicKeyOrToken) != 0;

            if (!definition.IsStrongName)
            {
                if (reference.IsStrongName)
                {
                    return(ComparisonResult.NotEquivalent);
                }

                if (!AssemblyIdentity.IsFullName(parts))
                {
                    if (!SimpleNameComparer.Equals(reference.Name, definition.Name))
                    {
                        return(ComparisonResult.NotEquivalent);
                    }

                    if (compareCulture && !CultureComparer.Equals(reference.CultureName, definition.CultureName))
                    {
                        return(ComparisonResult.NotEquivalent);
                    }

                    // version is ignored

                    return(ComparisonResult.Equivalent);
                }

                isDefinitionFxAssembly = false;
            }

            if (!SimpleNameComparer.Equals(reference.Name, definition.Name))
            {
                return(ComparisonResult.NotEquivalent);
            }

            if (compareCulture && !CultureComparer.Equals(reference.CultureName, definition.CultureName))
            {
                return(ComparisonResult.NotEquivalent);
            }

            if (comparePublicKeyToken && !AssemblyIdentity.KeysEqual(reference, definition))
            {
                return(ComparisonResult.NotEquivalent);
            }

            bool hasSomeVersionParts = (parts & AssemblyIdentityParts.Version) != 0;
            bool hasPartialVersion   = (parts & AssemblyIdentityParts.Version) != AssemblyIdentityParts.Version;

            // If any version parts were specified then compare the versions. The comparison fails if some version parts are missing.
            if (definition.IsStrongName &&
                hasSomeVersionParts &&
                (hasPartialVersion || reference.Version != definition.Version))
            {
                // Note:
                // System.Numerics.Vectors, Version=4.0 is an FX assembly
                // System.Numerics.Vectors, Version=4.1+ is not an FX assembly
                //
                // It seems like a bug in Fusion: it only determines whether the definition is an FX assembly
                // and calculates the result based upon that, regardless of whether the reference is an FX assembly or not.
                // We do replicate the behavior.
                //
                // As a result unification is asymmetric when comparing the above identities.
                if (isDefinitionFxAssembly)
                {
                    unificationApplied = true;
                    return(ComparisonResult.Equivalent);
                }

                if (ignoreVersion)
                {
                    return(ComparisonResult.EquivalentIgnoringVersion);
                }

                return(ComparisonResult.NotEquivalent);
            }

            return(ComparisonResult.Equivalent);
        }
        internal override bool ApplyUnificationPolicies(
            ref AssemblyIdentity reference,
            ref AssemblyIdentity definition,
            AssemblyIdentityParts referenceParts,
            out bool isDefinitionFxAssembly)
        {
            if (reference.ContentType == AssemblyContentType.Default &&
                SimpleNameComparer.Equals(reference.Name, definition.Name) &&
                SimpleNameComparer.Equals(reference.Name, "mscorlib"))
            {
                isDefinitionFxAssembly = true;
                reference = definition;
                return(true);
            }

            if (!reference.IsRetargetable && definition.IsRetargetable)
            {
                // Reference is not retargetable, but definition is retargetable.
                // Non-equivalent.
                isDefinitionFxAssembly = false;
                return(false);
            }

            // Notes:
            // an assembly might be both retargetable and portable
            // in that case retargetable table acts as an override.

            // Apply portability policy transforms first (e.g. rewrites references to SL assemblies to their desktop equivalents)
            // If the reference is partial and is missing version or PKT it is not ported.
            reference  = Port(reference);
            definition = Port(definition);

            if (reference.IsRetargetable && !definition.IsRetargetable)
            {
                if (!AssemblyIdentity.IsFullName(referenceParts))
                {
                    isDefinitionFxAssembly = false;
                    return(false);
                }

                // Reference needs to be retargeted before comparison,
                // unless it's optionally retargetable and we already match the PK
                bool skipRetargeting = IsOptionallyRetargetableAssembly(reference) &&
                                       AssemblyIdentity.KeysEqual(reference, definition);

                if (!skipRetargeting)
                {
                    reference = Retarget(reference);
                }
            }

            // At this point we are in one of the following states:
            //
            //   1) Both ref/def are not retargetable
            //   2) Both ref/def are retargetable
            //   3) Ref is retargetable (and has been retargeted)
            //
            // We can do a straight compare of ref/def at this point using the
            // regular rules

            if (reference.IsRetargetable && definition.IsRetargetable)
            {
                isDefinitionFxAssembly = IsRetargetableAssembly(definition);
            }
            else
            {
                isDefinitionFxAssembly = IsFrameworkAssembly(definition);
            }

            return(true);
        }