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); }
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); }
//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; } } } }
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); }
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); }
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); }
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); }
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; }
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; }
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; }
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); }
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); }
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; }
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); }
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; }
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); }
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); }
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, StringComparer.OrdinalIgnoreCase)); string contractConstraints = string.Join(",", GetConstraints(contractParam).OrderBy(s => s, StringComparer.OrdinalIgnoreCase)); 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); }
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; }
// TODO: Add support for property parameter lists public override DifferenceType Diff(IDifferences differences, MemberMapping mapping) { IMethodDefinition method1 = mapping[0] as IMethodDefinition; IMethodDefinition method2 = mapping[1] as IMethodDefinition; if (method1 == null && method2 == null) { return(DifferenceType.Unknown); } if (method1 != null && method2 != null) { return(DifferenceType.Unknown); } if (method1 != null) { IMethodDefinition match = FindBestMatch(method1, mapping.ContainingType, 1, 0); if (match != null) { differences.AddIncompatibleDifference(this, "Cannot change parameter types for method {0} and {1}", method1.GetMethodSignature(), match.GetMethodSignature()); return(DifferenceType.Changed); } } if (method2 != null) { IMethodDefinition match = FindBestMatch(method2, mapping.ContainingType, 0, 1); if (match != null) { differences.AddIncompatibleDifference(this, "Cannot change parameter types for method {0} and {1}", method2.GetMethodSignature(), match.GetMethodSignature()); return(DifferenceType.Changed); } } return(DifferenceType.Unknown); }
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); }
public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract) { if (contract != null && impl == null) { if (contract.ContainingTypeDefinition.IsInterface) { differences.AddIncompatibleDifference(this, contract.GetMemberViolationMessage($"{GetNameOfInterfaceMemberType(contract)}", $"is present in the {Contract}", $"not in the {Implementation}")); return(DifferenceType.Changed); } } if (impl != null && contract == null) { if (impl.ContainingTypeDefinition.IsInterface && !CanIgnoreAddedInterfaceMember(impl)) { differences.AddIncompatibleDifference(this, impl.GetMemberViolationMessage($"{GetNameOfInterfaceMemberType(impl)}", $"is present in the {Implementation}", $"not in the {Contract}")); return(DifferenceType.Changed); } } return(base.Diff(differences, impl, contract)); }
public override DifferenceType Diff(IDifferences differences, ITypeDefinitionMember impl, ITypeDefinitionMember contract) { if (contract != null && impl == null) { if (contract.ContainingTypeDefinition.IsInterface) { differences.AddIncompatibleDifference(this, $"Interface member '{contract.FullName()}' is present in the {Contract} but not in the {Implementation}."); return(DifferenceType.Changed); } } if (impl != null && contract == null) { if (impl.ContainingTypeDefinition.IsInterface && !CanIgnoreAddedInterfaceMember(impl)) { differences.AddIncompatibleDifference(this, $"Interface member '{impl.FullName()}' is present in the {Implementation} but not in the {Contract}."); return(DifferenceType.Changed); } } return(base.Diff(differences, impl, contract)); }
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)); }
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); }
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; }
// TODO: Add support for property parameter lists public override DifferenceType Diff(IDifferences differences, MemberMapping mapping) { IMethodDefinition method1 = mapping[0] as IMethodDefinition; IMethodDefinition method2 = mapping[1] as IMethodDefinition; if (method1 == null && method2 == null) return DifferenceType.Unknown; if (method1 != null && method2 != null) return DifferenceType.Unknown; if (method1 != null) { IMethodDefinition match = FindBestMatch(method1, mapping.ContainingType, 1, 0); if (match != null) { differences.AddIncompatibleDifference(this, "Cannot change parameter types for method {0} and {1}", method1.GetMethodSignature(), match.GetMethodSignature()); return DifferenceType.Changed; } } if (method2 != null) { IMethodDefinition match = FindBestMatch(method2, mapping.ContainingType, 0, 1); if (match != null) { differences.AddIncompatibleDifference(this, "Cannot change parameter types for method {0} and {1}", method2.GetMethodSignature(), match.GetMethodSignature()); return DifferenceType.Changed; } } return DifferenceType.Unknown; }
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; }
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); }
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; }
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); }
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; }
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; }
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); }
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); }
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 '{impl.FullName()}' is {(impl.IsSealed ? "actually (has the sealed modifier)" : "effectively (has a private constructor)")} sealed in the {Implementation} but not sealed in the {Contract}."); return(DifferenceType.Changed); } return(DifferenceType.Unknown); }
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; }
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 '{impl.FullName()}' is abstract in the {Implementation} but is not abstract in the {Contract}."); return(DifferenceType.Changed); } return(DifferenceType.Unknown); }
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", "Member '{0}' is abstract in the implementation but is not abstract in the contract.", impl.FullName()); return(DifferenceType.Changed); } return(DifferenceType.Unknown); }
// 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); } Debug.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); }
private bool AnyAttributeAdded(IDifferences differences, IReference target, IEnumerable <ICustomAttribute> implAttributes, IEnumerable <ICustomAttribute> contractAttributes) { bool added = false; AttributesMapping <IEnumerable <ICustomAttribute> > attributeMapping = new AttributesMapping <IEnumerable <ICustomAttribute> >(_settings); attributeMapping.AddMapping(0, implAttributes); attributeMapping.AddMapping(1, contractAttributes); foreach (var group in attributeMapping.Attributes) { switch (group.Difference) { case DifferenceType.Added: ITypeReference type = group.Representative.Attributes.First().Type; string attribName = type.FullName(); if (s_IgnorableAttributes.Contains(attribName)) { break; } differences.AddIncompatibleDifference(this, "Attribute '{0}' exists in the contract but not the implementation.", attribName, target.FullName()); added = true; 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: // Removing attributes is OK break; } } return(added); }
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); }
public override DifferenceType Diff(IDifferences differences, MemberMapping mapping) { ITypeDefinitionMember implMember = mapping[0]; ITypeDefinitionMember contractMember = mapping[1]; 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 incompatibleDifferenceMessage = contractMember.GetMemberViolationMessage("Member", $"does not exist in the {Implementation}", $"it does exist in the {Contract}"); ITypeDefinition contractType = mapping.ContainingType[0]; if (contractType != null) { if (contractMember is IMethodDefinition contractMethod) { // 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. if (FindMatchingMethodOnBase(contractType, contractMethod)) { return(DifferenceType.Unknown); } } } differences.AddIncompatibleDifference(this, incompatibleDifferenceMessage); return(DifferenceType.Added); }
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; }
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 '{contract.FullName()}' does not implement interface '{contractInterface.FullName()}' in the {Implementation} but it does in the {Contract}."); return true; } } return false; }
// 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; }
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; }
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, "Member '{0}' is abstract in the implementation but is missing in the contract.", impl.FullName()); return DifferenceType.Changed; } return DifferenceType.Unknown; }
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; }
private bool AnyAttributeAdded(IDifferences differences, IReference target, IEnumerable<ICustomAttribute> implAttributes, IEnumerable<ICustomAttribute> contractAttributes) { bool added = false; AttributesMapping<IEnumerable<ICustomAttribute>> attributeMapping = new AttributesMapping<IEnumerable<ICustomAttribute>>(_settings); attributeMapping.AddMapping(0, implAttributes); attributeMapping.AddMapping(1, contractAttributes); foreach (var group in attributeMapping.Attributes) { switch (group.Difference) { case DifferenceType.Added: ITypeReference type = group.Representative.Attributes.First().Type; string attribName = type.FullName(); if (s_IgnorableAttributes.Contains(attribName)) break; differences.AddIncompatibleDifference(this, "Attribute '{0}' exists in the contract but not the implementation.", attribName, target.FullName()); added = true; 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: // Removing attributes is OK break; } } return added; }
//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; } } } }