コード例 #1
0
        private DifferenceType Diff(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            if (implMethod == null || contractMethod == null)
                return DifferenceType.Unknown;

            return DiffConstraints(differences, implMethod, implMethod.GenericParameters, contractMethod.GenericParameters);
        }
コード例 #2
0
        public override DifferenceType Diff(IDifferences differences, Mappings.MemberMapping mapping)
        {
            ITypeDefinitionMember impl     = mapping[0];
            ITypeDefinitionMember contract = mapping[1];

            if (impl == null)
            {
                return(DifferenceType.Unknown);
            }

            if (contract == null && impl.IsAbstract())
            {
                // If the type is effectively sealed then it is ok to remove abstract members
                ITypeDefinition contractType = mapping.ContainingType[1];
                // We check that interfaces have the same number of members in another rule so there is no need to check that here.
                if (contractType != null && (contractType.IsEffectivelySealed() || (contractType.IsInterface && mapping.ContainingType[0].IsInterface)))
                {
                    return(DifferenceType.Unknown);
                }

                differences.AddIncompatibleDifference(this, impl.GetMemberViolationMessage("Member", $"is abstract in the {Implementation}", $"is missing in the {Contract}"));
                return(DifferenceType.Changed);
            }
            return(DifferenceType.Unknown);
        }
コード例 #3
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            // If implementation is public then contract can be any visibility
            if (impl.GetVisibility() == TypeMemberVisibility.Public)
            {
                return(DifferenceType.Unknown);
            }

            // If implementation is protected or protected internal then contract must be protected or protected internal as well.
            if (impl.GetVisibility() == TypeMemberVisibility.Family || impl.GetVisibility() == TypeMemberVisibility.FamilyOrAssembly)
            {
                if (contract.GetVisibility() != TypeMemberVisibility.Family && contract.GetVisibility() != TypeMemberVisibility.FamilyOrAssembly)
                {
                    differences.AddIncompatibleDifference(this,
                                                          $"Visibility of type '{impl.FullName()}' is '{impl.GetVisibility()}' in the {Implementation} but '{contract.GetVisibility()}' in the {Contract}.");
                    return(DifferenceType.Changed);
                }
            }

            return(DifferenceType.Unknown);
        }
コード例 #4
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (!impl.ContainingTypeDefinition.IsEnum || !contract.ContainingTypeDefinition.IsEnum)
                return DifferenceType.Unknown;

            IFieldDefinition implField = impl as IFieldDefinition;
            IFieldDefinition contractField = contract as IFieldDefinition;

            Contract.Assert(implField != null || contractField != null);

            string implValue = Convert.ToString(implField.Constant.Value);
            string contractValue = Convert.ToString(contractField.Constant.Value);

            // Calling the toString method to compare in since we might have the case where one Enum is type a and the other is type b, but they might still have same value.
            if (implValue != contractValue)
            {
                ITypeReference implValType = impl.ContainingTypeDefinition.GetEnumType();
                ITypeReference contractValType = contract.ContainingTypeDefinition.GetEnumType();

                differences.AddIncompatibleDifference(this,
                    "Enum value '{0}' is ({1}){2} in the implementation but ({3}){4} in the contract.",
                    implField.FullName(), implValType.FullName(), implField.Constant.Value,
                    contractValType.FullName(), contractField.Constant.Value);
                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #5
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            bool isImplOverridable     = IsOverridable(impl);
            bool isContractOverridable = IsOverridable(contract);

            /*
             * //@todo: Move to a separate rule that's only run in "strict" mode.
             * if (isImplInhertiable && !isContractInheritiable)
             * {
             *  // This is separate because it can be noisy and is generally allowed as long as it is reviewed properly.
             *  differences.AddIncompatibleDifference("CannotMakeMemberVirtual",
             *      "Member '{0}' is virtual in the implementation but non-virtual in the contract.",
             *      impl.FullName());
             *
             *  return DifferenceType.Changed;
             * }
             */

            if (isContractOverridable && !isImplOverridable)
            {
                differences.AddIncompatibleDifference("CannotMakeMemberNonVirtual",
                                                      $"Member '{impl.FullName()}' is non-virtual in the {Implementation} but is virtual in the {Contract}.");

                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #6
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            // If implementation is public then contract can be any visibility
            if (impl.Visibility == TypeMemberVisibility.Public)
            {
                return(DifferenceType.Unknown);
            }

            // If implementation is protected or protected internal then contract must be protected or protected internal as well.
            if (impl.Visibility == TypeMemberVisibility.Family || impl.Visibility == TypeMemberVisibility.FamilyOrAssembly)
            {
                if (contract.Visibility != TypeMemberVisibility.Family && contract.Visibility != TypeMemberVisibility.FamilyOrAssembly)
                {
                    differences.AddIncompatibleDifference(this,
                                                          "Visibility of member '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                                                          impl.FullName(), impl.Visibility, contract.Visibility);
                    return(DifferenceType.Changed);
                }
            }

            return(DifferenceType.Unknown);
        }
コード例 #7
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            if (!impl.ContainingTypeDefinition.IsEnum || !contract.ContainingTypeDefinition.IsEnum)
            {
                return(DifferenceType.Unknown);
            }

            IFieldDefinition implField     = impl as IFieldDefinition;
            IFieldDefinition contractField = contract as IFieldDefinition;

            Debug.Assert(implField != null || contractField != null);

            string implValue     = Convert.ToString(implField.Constant.Value);
            string contractValue = Convert.ToString(contractField.Constant.Value);

            // Calling the toString method to compare in since we might have the case where one Enum is type a and the other is type b, but they might still have same value.
            if (implValue != contractValue)
            {
                ITypeReference implValType     = impl.ContainingTypeDefinition.GetEnumType();
                ITypeReference contractValType = contract.ContainingTypeDefinition.GetEnumType();

                differences.AddIncompatibleDifference(this,
                                                      $"Enum value '{implField.FullName()}' is ({implValType.FullName()}){implField.Constant.Value} in the {Implementation} but ({contractValType.FullName()}){contractField.Constant.Value} in the {Contract}.");
                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #8
0
        private bool AddedBaseType(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            // For interfaces we rely only on the AddedInterface check
            if (impl.IsInterface || contract.IsInterface)
                return false;

            // Base types must be in the same order so we have to compare them in order
            List<ITypeReference> implBaseTypes = new List<ITypeReference>(impl.GetAllBaseTypes());

            int lastIndex = 0;
            foreach (var contractBaseType in contract.GetAllBaseTypes())
            {
                lastIndex = implBaseTypes.FindIndex(lastIndex, item1BaseType => _typeComparer.Equals(item1BaseType, contractBaseType));

                if (lastIndex < 0)
                {
                    differences.AddIncompatibleDifference(this,
                        "Type '{0}' does not inherit from base type '{1}' in the implementation but it does in the contract.",
                        contract.FullName(), contractBaseType.FullName());
                    return true;
                }
            }

            return false;
        }
コード例 #9
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            string implObjType     = GetObjectType(impl);
            string contractObjType = GetObjectType(contract);

            if (implObjType != contractObjType)
            {
                differences.AddIncompatibleDifference(this,
                                                      $"Type '{impl.FullName()}' is a '{implObjType}' in the {Implementation} but is a '{contractObjType}' in the {Contract}.");

                return(DifferenceType.Changed);
            }

            if (contract.Attributes.HasIsReadOnlyAttribute() && !impl.Attributes.HasIsReadOnlyAttribute())
            {
                differences.AddIncompatibleDifference(this,
                                                      $"Type '{impl.FullName()}' is marked as readonly in the {Contract} so it must also be marked readonly in the {Implementation}.");

                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #10
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            bool isImplOverridable = IsOverridable(impl);
            bool isContractOverridable = IsOverridable(contract);

            /*
            //@todo: Move to a separate rule that's only run in "strict" mode. 
            if (isImplInhertiable && !isContractInheritiable)
            {
                // This is separate because it can be noisy and is generally allowed as long as it is reviewed properly.
                differences.AddIncompatibleDifference("CannotMakeMemberVirtual",
                    "Member '{0}' is virtual in the implementation but non-virtual in the contract.",
                    impl.FullName());

                return DifferenceType.Changed;
            }
            */

            if (isContractOverridable && !isImplOverridable)
            {
                differences.AddIncompatibleDifference("CannotMakeMemberNonVirtual",
                    "Member '{0}' is non-virtual in the implementation but is virtual in the contract.",
                    impl.FullName());

                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #11
0
        private bool ParamNamesAndTypesMatch(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            int paramCount = implMethod.ParameterCount;

            Contract.Assert(paramCount == contractMethod.ParameterCount);

            IParameterDefinition[] implParams = implMethod.Parameters.ToArray();
            IParameterDefinition[] contractParams = contractMethod.Parameters.ToArray();

            bool match = true;
            for (int i = 0; i < paramCount; i++)
            {
                IParameterDefinition implParam = implParams[i];
                IParameterDefinition contractParam = contractParams[i];

                if (!implParam.Name.Value.Equals(contractParam.Name.Value))
                {
                    differences.AddIncompatibleDifference("DelegateParamNameMustMatch",
                        "Parameter name on delegate '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                        implMethod.ContainingType.FullName(), implParam.Name.Value, contractParam.Name.Value);
                    match = false;
                }

                if (!_typeComparer.Equals(implParam.Type, contractParam.Type))
                {
                    differences.AddTypeMismatchDifference("DelegateParamTypeMustMatch", implParam.Type, contractParam.Type,
                        "Type for parameter '{0}' on delegate '{1}' is '{2}' in the implementation but '{3}' in the contract.",
                        implParam.Name.Value, implMethod.ContainingType.FullName(), implParam.Type.FullName(), contractParam.Type.FullName());
                    match = false;
                }
            }
            return match;
        }
コード例 #12
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            // If implementation is public then contract can be any visibility
            if (impl.GetVisibility() == TypeMemberVisibility.Public)
            {
                return(DifferenceType.Unknown);
            }

            // If implementation is protected then contract must be protected as well.
            if (impl.GetVisibility() == TypeMemberVisibility.Family)
            {
                if (contract.GetVisibility() != TypeMemberVisibility.Family)
                {
                    differences.AddIncompatibleDifference(this,
                                                          "Visibility of type '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                                                          impl.FullName(), impl.GetVisibility(), contract.GetVisibility());
                    return(DifferenceType.Changed);
                }
            }

            return(DifferenceType.Unknown);
        }
コード例 #13
0
        private bool ParamNamesMatch(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            int paramCount = implMethod.ParameterCount;

            Contract.Assert(paramCount == contractMethod.ParameterCount);

            IParameterDefinition[] implParams = implMethod.Parameters.ToArray();
            IParameterDefinition[] contractParams = contractMethod.Parameters.ToArray();

            bool match = true;
            for (int i = 0; i < paramCount; i++)
            {
                IParameterDefinition implParam = implParams[i];
                IParameterDefinition contractParam = contractParams[i];

                if (!implParam.Name.Value.Equals(contractParam.Name.Value))
                {
                    differences.AddIncompatibleDifference(this,
                        "Parameter name on member '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                        implMethod.FullName(), implParam.Name.Value, contractParam.Name.Value);
                    match = false;
                }
            }
            return match;
        }
コード例 #14
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            if (!impl.IsEnum || !contract.IsEnum)
            {
                return(DifferenceType.Unknown);
            }

            ITypeReference implType     = impl.GetEnumType();
            ITypeReference contractType = contract.GetEnumType();

            if (!_typeComparer.Equals(implType, contractType))
            {
                differences.AddTypeMismatchDifference(this, implType, contractType,
                                                      "Enum type for '{0}' is '{1}' in implementation but '{2}' in the contract.",
                                                      impl.FullName(), implType.FullName(), contractType.FullName());
                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #15
0
        private bool ParamNamesMatch(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            int paramCount = implMethod.ParameterCount;

            Contract.Assert(paramCount == contractMethod.ParameterCount);

            IParameterDefinition[] implParams     = implMethod.Parameters.ToArray();
            IParameterDefinition[] contractParams = contractMethod.Parameters.ToArray();

            bool match = true;

            for (int i = 0; i < paramCount; i++)
            {
                IParameterDefinition implParam     = implParams[i];
                IParameterDefinition contractParam = contractParams[i];

                if (!implParam.Name.Value.Equals(contractParam.Name.Value))
                {
                    differences.AddIncompatibleDifference(this,
                                                          "Parameter name on member '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                                                          implMethod.FullName(), implParam.Name.Value, contractParam.Name.Value);
                    match = false;
                }
            }
            return(match);
        }
コード例 #16
0
        private bool AddedBaseType(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            // For interfaces we rely only on the AddedInterface check
            if (impl.IsInterface || contract.IsInterface)
            {
                return(false);
            }

            // Base types must be in the same order so we have to compare them in order
            List <ITypeReference> implBaseTypes = new List <ITypeReference>(impl.GetAllBaseTypes());

            int lastIndex = 0;

            foreach (var contractBaseType in contract.GetAllBaseTypes())
            {
                lastIndex = implBaseTypes.FindIndex(lastIndex, item1BaseType => _typeComparer.Equals(item1BaseType, contractBaseType));

                if (lastIndex < 0)
                {
                    differences.AddIncompatibleDifference(this,
                                                          $"Type '{contract.FullName()}' does not inherit from base type '{contractBaseType.FullName()}' in the {Implementation} but it does in the {Contract}.");
                    return(true);
                }
            }

            return(false);
        }
コード例 #17
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            return DiffConstraints(differences, impl, impl.GenericParameters, contract.GenericParameters);
        }
コード例 #18
0
        public void AddMapping(int index, TElement element)
        {
            if (index < 0 || index >= this.ElementCount)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            if (!_allowDuplicates && !this.Settings.IncludeForwardedTypes && _elements[index] != null)
            {
                // Could be useful under debugging but not an error because we have case like WPF
                // where the same type lives in multiple assemblies and we also have cases where members
                // appear to be the same because of modreq.
                Trace.TraceWarning("Duplicate element {0} in set!", element.ToString());
            }


            _differ          = null;
            _elements[index] = element;

            OnMappingAdded(index, element);
        }
コード例 #19
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            if (!impl.IsDelegate || !contract.IsDelegate)
            {
                return(DifferenceType.Unknown);
            }

            IMethodDefinition implMethod     = impl.GetInvokeMethod();
            IMethodDefinition contractMethod = contract.GetInvokeMethod();

            Debug.Assert(implMethod != null && contractMethod != null);

            if (!ReturnTypesMatch(differences, implMethod, contractMethod) ||
                !ParamNamesAndTypesMatch(differences, implMethod, contractMethod))
            {
                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #20
0
        private bool ParamNamesAndTypesMatch(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            int paramCount = implMethod.ParameterCount;

            Debug.Assert(paramCount == contractMethod.ParameterCount);

            IParameterDefinition[] implParams     = implMethod.Parameters.ToArray();
            IParameterDefinition[] contractParams = contractMethod.Parameters.ToArray();

            bool match = true;

            for (int i = 0; i < paramCount; i++)
            {
                IParameterDefinition implParam     = implParams[i];
                IParameterDefinition contractParam = contractParams[i];

                if (!implParam.Name.Value.Equals(contractParam.Name.Value))
                {
                    differences.AddIncompatibleDifference("DelegateParamNameMustMatch",
                                                          $"Parameter name on delegate '{implMethod.ContainingType.FullName()}' is '{implParam.Name.Value}' in the {Implementation} but '{contractParam.Name.Value}' in the {Contract}.");
                    match = false;
                }

                if (!_typeComparer.Equals(implParam.Type, contractParam.Type))
                {
                    differences.AddTypeMismatchDifference("DelegateParamTypeMustMatch", implParam.Type, contractParam.Type,
                                                          $"Type for parameter '{implParam.Name.Value}' on delegate '{implMethod.ContainingType.FullName()}' is '{implParam.Type.FullName()}' in the {Implementation} but '{contractParam.Type.FullName()}' in the {Contract}.");
                    match = false;
                }
            }
            return(match);
        }
コード例 #21
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            var implMethod     = impl as IMethodDefinition;
            var contractMethod = contract as IMethodDefinition;

            if (implMethod == null || contractMethod == null)
            {
                return(DifferenceType.Unknown);
            }

            bool changed = CheckAttributeDifferences(differences, implMethod, implMethod.Attributes, implMethod.Attributes);

            IParameterDefinition[] method1Params = implMethod.Parameters.ToArray();
            IParameterDefinition[] method2Params = contractMethod.Parameters.ToArray();
            for (int i = 0; i < implMethod.ParameterCount; i++)
            {
                changed |= CheckAttributeDifferences(differences, method1Params[i], method1Params[i].Attributes, method2Params[i].Attributes, member: implMethod);
            }

            if (implMethod.IsGeneric)
            {
                IGenericParameter[] method1GenParams = implMethod.GenericParameters.ToArray();
                IGenericParameter[] method2GenParam  = contractMethod.GenericParameters.ToArray();
                for (int i = 0; i < implMethod.GenericParameterCount; i++)
                {
                    changed |= CheckAttributeDifferences(differences, method1GenParams[i], method1GenParams[i].Attributes, method2GenParam[i].Attributes, member: implMethod);
                }
            }

            return(changed ? DifferenceType.Changed : DifferenceType.Unchanged);
        }
コード例 #22
0
 public static bool ContainsIncompatibleDifferences(this IDifferences differences)
 {
     if (differences.DifferenceType == DifferenceType.Changed)
     {
         return(!differences.OfType <IncompatibleDifference>().Any());
     }
     return(true);
 }
コード例 #23
0
        private bool CheckModifiersOnParametersAndReturnValue(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            int paramCount = implMethod.ParameterCount;

            Contract.Assert(paramCount == contractMethod.ParameterCount);

            if (paramCount == 0)
            {
                return(true);
            }

            IParameterDefinition[] implParams     = implMethod.Parameters.ToArray();
            IParameterDefinition[] contractParams = contractMethod.Parameters.ToArray();

            bool match = true;

            for (int i = 0; i < paramCount; i++)
            {
                IParameterDefinition implParam     = implParams[i];
                IParameterDefinition contractParam = contractParams[i];

                //TODO: Do we care about the compatibility with marshalling attributes Out\In? They don't seem to be set consistently.

                if (GetModifier(implParam) != GetModifier(contractParam))
                {
                    differences.AddIncompatibleDifference(this,
                                                          "Modifiers on parameter '{0}' on method '{1}' are '{2}' in the implementation but '{3}' in the contract.",
                                                          implParam.Name.Value, implMethod.FullName(), GetModifier(implParam), GetModifier(contractParam));
                    match = false;
                }

                // Now check custom modifiers, primarily focused on const & volatile
                if (implParam.IsModified || contractParam.IsModified)
                {
                    var union = implParam.CustomModifiers.Union(contractParam.CustomModifiers);
                    if (implParam.CustomModifiers.Count() != union.Count())
                    {
                        differences.AddIncompatibleDifference(this,
                                                              "Custom modifiers on parameter '{0}' on method '{1}' are '{2}' in the implementation but '{3}' in the contract.",
                                                              implParam.Name.Value, implMethod.FullName(), PrintCustomModifiers(implParam.CustomModifiers), PrintCustomModifiers(contractParam.CustomModifiers));
                        match = false;
                    }
                }
            }

            string implReturnModifier     = GetReturnValueModifier(implMethod);
            string contractReturnModifier = GetReturnValueModifier(contractMethod);

            if (implReturnModifier != contractReturnModifier)
            {
                differences.AddIncompatibleDifference(this,
                                                      "Modifiers on return type of method '{0}' are '{1}' in the implementation but '{2}' in the contract.",
                                                      implMethod.FullName(), implReturnModifier, contractReturnModifier);
                match = false;
            }

            return(match);
        }
コード例 #24
0
        private DifferenceType Diff(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            if (implMethod == null || contractMethod == null)
            {
                return(DifferenceType.Unknown);
            }

            return(DiffConstraints(differences, implMethod, implMethod.GenericParameters, contractMethod.GenericParameters));
        }
コード例 #25
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            return(CheckAttributeDifferences(differences, impl, impl.Attributes, contract.Attributes));
        }
コード例 #26
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            return(DiffConstraints(differences, impl, impl.GenericParameters, contract.GenericParameters));
        }
コード例 #27
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            //            if (AnyAttributeAdded(differences, impl, impl.Attributes, contract.Attributes))
            //                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #28
0
        public List <IScriptBlock> GenerateScript(IDifferences differences, ScriptDirection direction, Options options)
        {
            var blocks = new List <IScriptBlock>(differences.Count);

            foreach (var difference in differences)
            {
                if (!difference.UseInGeneration)
                {
                    continue;
                }

                IScriptableObject sourceObj = difference.DatabaseObjectA;
                IScriptableObject targetObj = difference.DatabaseObjectB;

                DifferenceType differenceType = difference.Type;

                // If the direction FromBToA, flip it around
                if (direction == ScriptDirection.FromBToA)
                {
                    sourceObj = difference.DatabaseObjectB;
                    targetObj = difference.DatabaseObjectA;

                    // Swap the 'OnlyIn' type if it is one of them
                    if (differenceType == DifferenceType.OnlyInA)
                    {
                        differenceType = DifferenceType.OnlyInB;
                    }
                    else if (differenceType == DifferenceType.OnlyInB)
                    {
                        differenceType = DifferenceType.OnlyInA;
                    }
                }

                // Add the block/s for this difference
                switch (differenceType)
                {
                case DifferenceType.Different:
                    blocks.AddRange(sourceObj.AlterTo(targetObj, options));
                    break;

                case DifferenceType.OnlyInA:
                    blocks.Add(sourceObj.DropBlock(options));
                    break;

                case DifferenceType.OnlyInB:
                    blocks.Add(targetObj.CreateBlock(options));
                    break;
                }
            }

            // Filter out any null values before returning
            blocks = blocks.Where(block => block != null).ToList();

            return(blocks);
        }
コード例 #29
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (AddedBaseType(differences, impl, contract) ||
                AddedInterface(differences, impl, contract))
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #30
0
 public static void AddIncompatibleDifference(this IDifferences differences, object id, string format, params object[] args)
 {
     if (args.Length == 0)
     {
         differences.Add(new IncompatibleDifference(id, format));
     }
     else
     {
         differences.Add(new IncompatibleDifference(id, string.Format(format, args)));
     }
 }
コード例 #31
0
 public static void AddTypeMismatchDifference(this IDifferences differences, object id, ITypeReference type1, ITypeReference type2, string format, params object[] args)
 {
     if (args.Length == 0)
     {
         differences.Add(new TypeMismatchInCompatibleDifference(id, format, type1, type2));
     }
     else
     {
         differences.Add(new TypeMismatchInCompatibleDifference(id, string.Format(format, args), type1, type2));
     }
 }
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (AddedBaseType(differences, impl, contract) ||
                AddedInterface(differences, impl, contract))
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #33
0
        //private bool AnySecurityAttributeAdded(IDifferences differences, IReference target, IEnumerable<ISecurityAttribute> attribues1, IEnumerable<ISecurityAttribute> attributes2)
        //{
        //    return AnyAttributeAdded(differences, target, attribues1.SelectMany(a => a.Attributes), attributes2.SelectMany(a => a.Attributes));
        //}

        private void CheckAttributeDifferences(IDifferences differences, IReference target, IEnumerable <ICustomAttribute> implAttributes, IEnumerable <ICustomAttribute> contractAttributes)
        {
            AttributesMapping <IEnumerable <ICustomAttribute> > attributeMapping = new AttributesMapping <IEnumerable <ICustomAttribute> >(_settings);

            attributeMapping.AddMapping(0, contractAttributes);
            attributeMapping.AddMapping(1, implAttributes);

            foreach (var group in attributeMapping.Attributes)
            {
                switch (group.Difference)
                {
                case DifferenceType.Added:
                {
                    ITypeReference type       = group.Representative.Attributes.First().Type;
                    string         attribName = type.FullName();

                    if (FilterAttribute(attribName))
                    {
                        break;
                    }

                    AttributeAdded(target, attribName);

                    differences.AddIncompatibleDifference("CannotAddAttribute",
                                                          "Attribute '{0}' exists on '{1}' in the implementation but not the contract.",
                                                          attribName, target.FullName());

                    break;
                }

                case DifferenceType.Changed:

                    //TODO: Add some more logic to check the two lists of attributes which have the same type.
                    break;

                case DifferenceType.Removed:
                {
                    ITypeReference type       = group.Representative.Attributes.First().Type;
                    string         attribName = type.FullName();

                    if (s_IgnorableAttributes.Contains(attribName))
                    {
                        break;
                    }

                    differences.AddIncompatibleDifference("CannotRemoveAttribute",
                                                          "Attribute '{0}' exists on '{1}' in the contract but not the implementation.",
                                                          attribName, target.FullName());

                    break;
                }
                }
            }
        }
コード例 #34
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            //            if (AnyAttributeAdded(differences, impl, impl.Attributes, contract.Attributes))
            //                return DifferenceType.Changed;

            return(DifferenceType.Unknown);
        }
コード例 #35
0
ファイル: MembersMustExist.cs プロジェクト: omajid/arcade
        public override DifferenceType Diff(IDifferences differences, MemberMapping mapping)
        {
            ITypeDefinitionMember implMember     = mapping[0];
            ITypeDefinitionMember contractMember = mapping[1];
            IMethodDefinition     foundMethod;

            if (!(implMember == null && contractMember != null))
            {
                return(DifferenceType.Unknown);
            }

            // Nested types are handled separately.
            // @TODO: Events and Properties - should we consider these too (or rely on the fact that dropping one of these will also drop their accessors.)
            if (!(contractMember is IMethodDefinition || contractMember is IFieldDefinition))
            {
                return(DifferenceType.Unknown);
            }

            string incompatibeDifferenceMessage = $"Member '{contractMember.FullName()}' does not exist in the {Implementation} but it does exist in the {Contract}.";

            ITypeDefinition contractType = mapping.ContainingType[0];

            if (contractType != null)
            {
                IMethodDefinition contractMethod = contractMember as IMethodDefinition;
                if (contractMethod != null)
                {
                    // If the contract is a Explicit Interface method, we don't need to check if the method is in implementation since that will be caught by different rule.
                    if (contractMethod.IsExplicitInterfaceMethod())
                    {
                        return(DifferenceType.Unknown);
                    }



                    // It is valid to promote a member from a base type up so check to see if it member exits on a base type.
                    var lookForMethodInBaseResult = FindMatchingBase(contractType, contractMethod, out foundMethod);
                    if (lookForMethodInBaseResult == FindMethodResult.Found)
                    {
                        return(DifferenceType.Unknown);
                    }
                    if (lookForMethodInBaseResult == FindMethodResult.ReturnTypeChanged)
                    {
                        incompatibeDifferenceMessage += $" There does exist a member with return type '{foundMethod.GetReturnType().FullName()}' instead of '{contractMethod.GetReturnType().FullName()}'";
                    }
                }
            }

            differences.AddIncompatibleDifference(this, incompatibeDifferenceMessage);

            return(DifferenceType.Added);
        }
コード例 #36
0
ファイル: TypesMustExist.cs プロジェクト: dsgouda/buildtools
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null && contract != null)
            {
                if (!ReportAsMembersMustExist(contract, differences))
                {
                    differences.AddIncompatibleDifference(this,
                        "Type '{0}' does not exist in the implementation but it does exist in the contract.", contract.FullName());
                }

                return DifferenceType.Added;
            }

            return DifferenceType.Unknown;
        }
コード例 #37
0
ファイル: TypesMustExist.cs プロジェクト: dsgouda/buildtools
 // Usability hack: Ordinarily, removing a type does not trigger secondary messages about removing its members. Normally,
 // this is very useful behavior. However, this backfires in the case where a type "vanishes" solely because someone removed 
 // its last [TreatAsPublicSurface] member. [TreatAsPublicSurface] is the only known case where one can "remove" a type merely 
 // by changing something about one of its members - something that has no precedent in the minds of most developers.
 // Reporting the violation as a removal of the type would be quite unhelpful in this case. Thus, if the "removed" type
 // had one or more [TreatAsPublicSurface] members, we counterfeit a MembersMustExist message.
 private bool ReportAsMembersMustExist(ITypeDefinition contract, IDifferences differences)
 {
     bool specialCasedViolation = false;
     //foreach (ITypeDefinitionMember member in contract.Members)
     //{
     //    if (member.MarkedAsPublicSurface())
     //    {
     //        differences.AddIncompatibleDifference(
     //            "MembersMustExist",
     //            "Member '{0}' does not exist in the implementation but it does exist in the contract.", member.FullName());
     //        specialCasedViolation = true;
     //    }
     //}
     return specialCasedViolation;
 }
コード例 #38
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null && contract != null)
            {
                if (!ReportAsMembersMustExist(contract, differences))
                {
                    differences.AddIncompatibleDifference(this,
                                                          "Type '{0}' does not exist in the implementation but it does exist in the contract.", contract.FullName());
                }

                return(DifferenceType.Added);
            }

            return(DifferenceType.Unknown);
        }
コード例 #39
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            bool added = false;

            //added |= AnyAttributeAdded(differences, impl, impl.Attributes, contract.Attributes);
            //added |= AnyMethodSpecificAttributeAdded(differences, impl as IMethodDefinition, contract as IMethodDefinition);

            if (added)
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #40
0
ファイル: CannotSealType.cs プロジェクト: dsgouda/buildtools
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (impl.IsEffectivelySealed() && !contract.IsEffectivelySealed())
            {
                differences.AddIncompatibleDifference(this,
                    "Type '{0}' is sealed in the implementation but not sealed in the contract.", impl.FullName());

                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #41
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (ImplementsIDisposable(impl) && !ImplementsIDisposable(contract))
            {
                differences.AddIncompatibleDifference(this,
                    "Type '{0}' implements IDisposable in the implementation but not the contract.",
                    impl.FullName());
                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #42
0
ファイル: CannotMakeAbstract.cs プロジェクト: sfoslund/arcade
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            if (impl.IsAbstract() && !contract.IsAbstract())
            {
                differences.AddIncompatibleDifference("CannotMakeMemberAbstract", impl.GetMemberViolationMessage("Member", $"is abstract in the {Implementation}", $"is not abstract in the {Contract}"));
                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #43
0
        // Usability hack: Ordinarily, removing a type does not trigger secondary messages about removing its members. Normally,
        // this is very useful behavior. However, this backfires in the case where a type "vanishes" solely because someone removed
        // its last [TreatAsPublicSurface] member. [TreatAsPublicSurface] is the only known case where one can "remove" a type merely
        // by changing something about one of its members - something that has no precedent in the minds of most developers.
        // Reporting the violation as a removal of the type would be quite unhelpful in this case. Thus, if the "removed" type
        // had one or more [TreatAsPublicSurface] members, we counterfeit a MembersMustExist message.
        private bool ReportAsMembersMustExist(ITypeDefinition contract, IDifferences differences)
        {
            bool specialCasedViolation = false;

            //foreach (ITypeDefinitionMember member in contract.Members)
            //{
            //    if (member.MarkedAsPublicSurface())
            //    {
            //        differences.AddIncompatibleDifference(
            //            "MembersMustExist",
            //            "Member '{0}' does not exist in the implementation but it does exist in the contract.", member.FullName());
            //        specialCasedViolation = true;
            //    }
            //}
            return(specialCasedViolation);
        }
コード例 #44
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
            {
                return(DifferenceType.Unknown);
            }

            if (ImplementsIDisposable(impl) && !ImplementsIDisposable(contract))
            {
                differences.AddIncompatibleDifference(this,
                                                      $"Type '{impl.FullName()}' implements IDisposable in the {Implementation} but not the {Contract}.");
                return(DifferenceType.Changed);
            }

            return(DifferenceType.Unknown);
        }
コード例 #45
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (impl.IsAbstract && !contract.IsAbstract)
            {
                differences.AddIncompatibleDifference("CannotMakeTypeAbstract",
                    "Type '{0}' is abstract in the implementation but is not abstract in the contract.",
                    impl.FullName());

                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #46
0
        public override DifferenceType Diff(IDifferences differences, IAssembly impl, IAssembly contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            bool added = false;

            //added |= AnyAttributeAdded(differences, impl, impl.AssemblyAttributes, contract.AssemblyAttributes);
            //added |= AnyAttributeAdded(differences, impl, impl.ModuleAttributes, contract.ModuleAttributes);
            //added |= AnySecurityAttributeAdded(differences, impl, impl.SecurityAttributes, contract.SecurityAttributes);

            if (added)
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #47
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            IMethodDefinition implMethod = impl as IMethodDefinition;
            IMethodDefinition contractMethod = contract as IMethodDefinition;

            if (implMethod == null || contractMethod == null)
                return DifferenceType.Unknown;

            if (!ParamNamesMatch(differences, implMethod, contractMethod))
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #48
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            IMethodDefinition method1 = impl as IMethodDefinition;
            IMethodDefinition method2 = contract as IMethodDefinition;

            if (method1 == null || method2 == null)
                return DifferenceType.Unknown;

            if (!ParamModifiersMatch(differences, method1, method2))
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #49
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            string implObjType = GetObjectType(impl);
            string contractObjType = GetObjectType(contract);

            if (implObjType != contractObjType)
            {
                differences.AddIncompatibleDifference(this,
                    "Type '{0}' is a {1} in the implementation but is a {2} in the contract.",
                    impl.FullName(), implObjType, contractObjType);
            }

            return DifferenceType.Unknown;
        }
コード例 #50
0
        private bool ReturnTypesMatch(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            ITypeReference implReturnType = implMethod.GetReturnType();
            ITypeReference contractReturnType = contractMethod.GetReturnType();

            if (implReturnType == null || contractReturnType == null)
                return true;

            if (!_typeComparer.Equals(implReturnType, contractReturnType))
            {
                differences.AddTypeMismatchDifference("DelegateReturnTypesMustMatch", implReturnType, contractReturnType,
                    "Return type on delegate '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                    implMethod.ContainingType.FullName(), implReturnType.FullName(), contractReturnType.FullName());
                return false;
            }

            return true;
        }
コード例 #51
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (!impl.IsDelegate || !contract.IsDelegate)
                return DifferenceType.Unknown;

            IMethodDefinition implMethod = impl.GetInvokeMethod();
            IMethodDefinition contractMethod = contract.GetInvokeMethod();

            Contract.Assert(implMethod != null && contractMethod != null);

            if (!ReturnTypesMatch(differences, implMethod, contractMethod) ||
                !ParamNamesAndTypesMatch(differences, implMethod, contractMethod))
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #52
0
        private bool ParamModifiersMatch(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            int paramCount = implMethod.ParameterCount;

            Contract.Assert(paramCount == contractMethod.ParameterCount);

            if (paramCount == 0)
                return true;

            IParameterDefinition[] implParams = implMethod.Parameters.ToArray();
            IParameterDefinition[] contractParams = contractMethod.Parameters.ToArray();

            bool match = true;
            for (int i = 0; i < paramCount; i++)
            {
                IParameterDefinition implParam = implParams[i];
                IParameterDefinition contractParam = contractParams[i];

                //TODO: Do we care about the compatibility with marshalling attributes Out\In? They don't seem to be set consistently.

                if (GetModifier(implParam) != GetModifier(contractParam))
                {
                    differences.AddIncompatibleDifference(this,
                        "Modifiers on parameter '{0}' on method '{1}' are '{2}' in the implementation but '{3}' in the contract.",
                        implParam.Name.Value, implMethod.FullName(), GetModifier(implParam), GetModifier(contractParam));
                    match = false;
                }

                // Now check custom modifiers, primarily focused on const & volatile
                if (implParam.IsModified || contractParam.IsModified)
                {
                    var union = implParam.CustomModifiers.Union(contractParam.CustomModifiers);
                    if (implParam.CustomModifiers.Count() != union.Count())
                    {
                        differences.AddIncompatibleDifference(this,
                            "Custom modifiers on parameter '{0}' on method '{1}' are '{2}' in the implementation but '{3}' in the contract.",
                            implParam.Name.Value, implMethod.FullName(), PrintCustomModifiers(implParam.CustomModifiers), PrintCustomModifiers(contractParam.CustomModifiers));
                        match = false;
                    }
                }
            }
            return match;
        }
コード例 #53
0
        private bool AnyMethodSpecificAttributeAdded(IDifferences differences, IMethodDefinition implMethod, IMethodDefinition contractMethod)
        {
            if (implMethod == null || contractMethod == null)
                return false;

            bool added = false;

            added |= AnyAttributeAdded(differences, implMethod, implMethod.ReturnValueAttributes, contractMethod.ReturnValueAttributes);
            added |= AnySecurityAttributeAdded(differences, implMethod, implMethod.SecurityAttributes, contractMethod.SecurityAttributes);

            Contract.Assert(implMethod.ParameterCount == contractMethod.ParameterCount);

            IParameterDefinition[] method1Params = implMethod.Parameters.ToArray();
            IParameterDefinition[] method2Params = contractMethod.Parameters.ToArray();
            for (int i = 0; i < implMethod.ParameterCount; i++)
                added |= AnyAttributeAdded(differences, method1Params[i], method1Params[i].Attributes, method2Params[i].Attributes);

            return added;
        }
コード例 #54
0
        public override DifferenceType Diff(IDifferences differences, MemberMapping mapping)
        {
            ITypeDefinitionMember implMember = mapping[0];
            ITypeDefinitionMember contractMember = mapping[1];
            IMethodDefinition foundMethod;

            if (!(implMember == null && contractMember != null))
                return DifferenceType.Unknown;

            // Nested types are handled separately.
            // @TODO: Events and Properties - should we consider these too (or rely on the fact that dropping one of these will also drop their accessors.) 
            if (!(contractMember is IMethodDefinition || contractMember is IFieldDefinition))
                return DifferenceType.Unknown;

            string incompatibeDifferenceMessage = string.Format("Member '{0}' does not exist in the implementation but it does exist in the contract.", contractMember.FullName());
            string returnTypeChangedMessageFormat = "Member '{0}' does not exist, but there does exist a member with return type '{1}' instead of '{2}'";
            ITypeDefinition contractType = mapping.ContainingType[0];
            if (contractType != null)
            {
                IMethodDefinition contractMethod = contractMember as IMethodDefinition;
                if (contractMethod != null)
                {
                    // If the contract is a Explicit Interface method, we don't need to check if the method is in implementation since that will be catched by different rule.
                    if (contractMethod.IsExplicitInterfaceMethod())
                        return DifferenceType.Unknown;



                    // It is valid to promote a member from a base type up so check to see if it member exits on a base type.
                    var lookForMethodInBaseResult = FindMatchingBase(contractType, contractMethod, out foundMethod);
                    if (lookForMethodInBaseResult == FindMethodResult.Found)
                        return DifferenceType.Unknown;
                    if (lookForMethodInBaseResult == FindMethodResult.ReturnTypeChanged)
                        incompatibeDifferenceMessage = string.Format(returnTypeChangedMessageFormat, foundMethod.FullName(), foundMethod.GetReturnType().FullName(), contractMethod.GetReturnType().FullName());
                }
            }

            differences.AddIncompatibleDifference(this, incompatibeDifferenceMessage);

            return DifferenceType.Added;
        }
コード例 #55
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            if (!impl.IsEnum || !contract.IsEnum)
                return DifferenceType.Unknown;

            ITypeReference implType = impl.GetEnumType();
            ITypeReference contractType = contract.GetEnumType();

            if (!_typeComparer.Equals(implType, contractType))
            {
                differences.AddTypeMismatchDifference(this, implType, contractType,
                    "Enum type for '{0}' is '{1}' in implementation but '{2}' in the contract.",
                    impl.FullName(), implType.FullName(), contractType.FullName());
                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #56
0
        // Consider the following object hierarchy.  Remember we are not enforcing a subset relationship
        // on both types.  Our goal is to build a third API that is a subset of both, with versioning rules
        // that will produce a consistent universe with both new frameworks.
        //             Object
        //        Fruit        Shape
        //       Apple
        //      Red Delicious
        // 
        // 1) A type is not reparented across the hierarchy.  (ie, Apple may subclass Object, but may not subclass Shape)
        // 2) Removing a type like Apple from the inheritance hierarchy is legal, BUT all new methods on Apple must be
        //    duplicated on Red Delicious.  (Methods will be tracked in a separate rule)
        // 3) If you removed a type like Apple, then all overridden methods from Fruit & higher should be
        //    re-overridden by Red Delicious to ensure behavior is compatible.  (methods will be tracked in a separate rule)
        // 4) It is legal to add a type like Fruit into the hierarchy - consider this the reverse of #2.
        // 5) If one Framework had Object -> NewType -> Apple, that is only legal if NewType is in the other 
        //    Framework's inheritance hierarchy somewhere between Object and Apple.  IE, NewType could be 
        //    "Food" or "RoundFruit", but could not be "Shape"
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition item1, ITypeDefinition item2)
        {
            if (item1 == null || item2 == null)
                return DifferenceType.Unknown;

            Contract.Assert(_typeComparer != null);

            IEnumerable<ITypeReference> item1BaseClassChain = GetBaseClassChain(item1);
            IEnumerable<ITypeReference> item2BaseClassChain = GetBaseClassChain(item2);

            bool added = item2BaseClassChain.Except(item1BaseClassChain, _typeComparer).Any(t => true);
            bool removed = item1BaseClassChain.Except(item2BaseClassChain, _typeComparer).Any(t => true);

            // To a first approximation, we cannot both add base types and remove base types.
            // IE, we cannot take an Apple, remove Fruit and add Shape.
            // However there are more pathologically complicated inheritance hierarchies that are linear but where we 
            // add one type & remove another.  If both additions & removals occur, they're only legal if one of those 
            // added or removed types subclasses the other one.  We do not currently check for that.
            if (added && removed)
            {
                // Special case for DependencyObject and its derived types
                if (item1BaseClassChain.Any((type) => TypeHelper.GetTypeName(type) == "System.Windows.DependencyObject") &&
                    item2BaseClassChain.Any((type) => TypeHelper.GetTypeName(type) == "Windows.UI.DirectUI.DependencyObject"))
                {
                    // If the new type name is the same as the old type name in a new namespace, let's consider that a known issue.
                    String oldBaseTypeName = TypeHelper.GetTypeName(item1BaseClassChain.First());
                    String newBaseTypeName = TypeHelper.GetTypeName(item2BaseClassChain.First());
                    oldBaseTypeName = oldBaseTypeName.Replace("System.Windows", "Windows.UI.DirectUI");
                    if (oldBaseTypeName == newBaseTypeName)
                        return DifferenceType.Unknown;
                }

                differences.AddIncompatibleDifference(this,
                    "Type {0} or one of its base classes was reparented in an incompatible way.  Old base classes: {1}  New Base Classes: {2}",
                    item1.FullName(), PrintClassHierarchy(item1BaseClassChain), PrintClassHierarchy(item2BaseClassChain));
                return DifferenceType.Changed;
            }

            return DifferenceType.Unknown;
        }
コード例 #57
0
        private DifferenceType DiffConstraints(IDifferences differences, IReference target, IEnumerable<IGenericParameter> implGenericParams, IEnumerable<IGenericParameter> contractGenericParams)
        {
            int beforeCount = differences.Count();
            IGenericParameter[] implParams = implGenericParams.ToArray();
            IGenericParameter[] contractParams = contractGenericParams.ToArray();

            // We shoudn't hit this because the types/members shouldn't be matched up if they have different generic argument lists
            if (implParams.Length != contractParams.Length)
                return DifferenceType.Changed;

            for (int i = 0; i < implParams.Length; i++)
            {
                IGenericParameter implParam = implParams[i];
                IGenericParameter contractParam = contractParams[i];

                if (contractParam.Variance != TypeParameterVariance.NonVariant &&
                    contractParam.Variance != implParam.Variance)
                {
                    differences.AddIncompatibleDifference("CannotChangeVariance",
                        "Variance on generic parameter '{0}' for '{1}' is '{2}' in the implementation but '{3}' in the contract.",
                        implParam.FullName(), target.FullName(), implParam.Variance, contractParam.Variance);
                }

                string implConstraints = string.Join(",", GetConstraints(implParam).OrderBy(s => s));
                string contractConstraints = string.Join(",", GetConstraints(contractParam).OrderBy(s => s));

                if (!string.Equals(implConstraints, contractConstraints))
                {
                    differences.AddIncompatibleDifference("CannotChangeGenericConstraints",
                        "Constraints for generic parameter '{0}' for '{1}' is '{2}' in the implementation but '{3}' in the contract.",
                        implParam.FullName(), target.FullName(), implConstraints, contractConstraints);
                }
            }

            if (differences.Count() != beforeCount)
                return DifferenceType.Changed;

            return DifferenceType.Unknown;
        }
コード例 #58
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract)
        {
            if (contract != null && impl == null)
            {
                if (contract.ContainingTypeDefinition.IsInterface)
                {
                    differences.AddIncompatibleDifference(this, "Contract interface member '{0}' is not in the implementation.", contract.FullName());
                    return DifferenceType.Changed;
                }
            }

            if (impl != null && contract == null)
            {
                if (impl.ContainingTypeDefinition.IsInterface)
                {
                    differences.AddIncompatibleDifference(this, "Implementation interface member '{0}' is not in the contract.", impl.FullName());
                    return DifferenceType.Changed;
                }
            }

            return base.Diff(differences, impl, contract);
        }
コード例 #59
0
        private bool AddedInterface(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            // Interfaces can be in any order so use a HashSet
            HashSet<ITypeReference> implInterfaces = new HashSet<ITypeReference>(impl.GetAllInterfaces(), _typeComparer);

            foreach (var contractInterface in contract.GetAllInterfaces())
            {
                // Ignore internal interfaces
                if (!contractInterface.IsVisibleOutsideAssembly())
                    continue;

                if (!implInterfaces.Contains(contractInterface))
                {
                    differences.AddIncompatibleDifference(this,
                        "Type '{0}' does not implement interface '{1}' in the implementation but it does in the contract.",
                            contract.FullName(), contractInterface.FullName());
                    return true;
                }
            }

            return false;
        }
コード例 #60
0
        public override DifferenceType Diff(IDifferences differences, ITypeDefinition impl, ITypeDefinition contract)
        {
            if (impl == null || contract == null)
                return DifferenceType.Unknown;

            // If implementation is public then contract can be any visibility
            if (impl.GetVisibility() == TypeMemberVisibility.Public)
                return DifferenceType.Unknown;

            // If implementation is protected then contract must be protected as well. 
            if (impl.GetVisibility() == TypeMemberVisibility.Family)
            {
                if (contract.GetVisibility() != TypeMemberVisibility.Family)
                {
                    differences.AddIncompatibleDifference(this,
                        "Visibility of type '{0}' is '{1}' in the implementation but '{2}' in the contract.",
                        impl.FullName(), impl.GetVisibility(), contract.GetVisibility());
                    return DifferenceType.Changed;
                }
            }

            return DifferenceType.Unknown;
        }