private static void EvaluateArgumentDefinitionChanges( ItemMatch <IAttributeDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { if (EvaluateArgumentCount(match, options, aggregator)) { return; } if (EvaluateOrdinalArgumentCount(match, options, aggregator)) { return; } // No need to check for a difference in named argument counts because at this point we have the same number of overall arguments and the same number of ordinal arguments // The number of named arguments must be the same // At this point we have the same number of ordinal and named arguments if (EvaluateOrdinalArgument(match, options, aggregator)) { return; } EvaluateNamedArgument(match, options, aggregator); }
private static void EvaluateDefaultValueChanges( ItemMatch <IParameterDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldItem = match.OldItem; var newItem = match.NewItem; if (string.IsNullOrWhiteSpace(oldItem.DefaultValue) && string.IsNullOrWhiteSpace(newItem.DefaultValue) == false) { // A default value has been added, this is technically a feature because the consuming assembly can treat it like an overload var args = new FormatArguments( "{DefinitionType} {Identifier} has added the default value {NewValue}", match.NewItem.FullName, null, newItem.DefaultValue); aggregator.AddElementChangedResult(SemVerChangeType.Feature, match, options.MessageFormatter, args); } else if (string.IsNullOrWhiteSpace(oldItem.DefaultValue) == false && string.IsNullOrWhiteSpace(newItem.DefaultValue)) { // A default value has been removed // This will not be a breaking change for existing applications that happen to use a new binary without recompilation // however it does cause a breaking change for compiling existing applications against this API var args = new FormatArguments( "{DefinitionType} {Identifier} has removed the default value {OldValue}", match.NewItem.FullName, oldItem.DefaultValue, null); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); } }
private static bool EvaluateOrdinalArgument(ItemMatch <IAttributeDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldArguments = match.OldItem.Arguments.Where(x => x.ArgumentType == ArgumentType.Ordinal).ToList(); var newArguments = match.NewItem.Arguments.Where(x => x.ArgumentType == ArgumentType.Ordinal).ToList(); for (var index = 0; index < oldArguments.Count; index++) { var oldArgument = oldArguments[index]; var newArgument = newArguments[index]; if (oldArgument.Value != newArgument.Value) { var args = new FormatArguments( "{DefinitionType} {Identifier} has changed value from {OldValue} to {NewValue}", (index + 1).ToString(), oldArgument.Value, newArgument.Value); // Create a match for the arguments var argumentMatch = new ItemMatch <IArgumentDefinition>(oldArgument, newArgument); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, argumentMatch, options.MessageFormatter, args); return(true); } } return(false); }
private static bool EvaluateArgumentCount(ItemMatch <IAttributeDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldArguments = match.OldItem.Arguments.Count; var newArguments = match.NewItem.Arguments.Count; var argumentShift = oldArguments - newArguments; if (argumentShift != 0) { // One or more arguments have been added or removed var changeLabel = argumentShift > 0 ? "removed" : "added"; var shiftAmount = Math.Abs(argumentShift); var suffix = shiftAmount == 1 ? "" : "s"; var args = new FormatArguments( $"{{DefinitionType}} {{Identifier}} has {changeLabel} {shiftAmount} argument{suffix}", match.NewItem.Name, null, null); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); // No need to look into how the attribute has changed return(true); } return(false); }
private void EvaluateFieldChanges( ItemMatch <IClassDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var changes = _fieldProcessor.CalculateChanges(match.OldItem.Fields, match.NewItem.Fields, options); aggregator.AddResults(changes); }
protected override void EvaluateSignatureChanges(ItemMatch <T> match, ComparerOptions options, IChangeResultAggregator aggregator) { match = match ?? throw new ArgumentNullException(nameof(match)); options = options ?? throw new ArgumentNullException(nameof(options)); base.EvaluateSignatureChanges(match, options, aggregator); RunComparisonStep(EvaluateReturnTypeChanges, match, options, aggregator, true); }
protected override void EvaluateChildElementChanges(ItemMatch <IClassDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { match = match ?? throw new ArgumentNullException(nameof(match)); options = options ?? throw new ArgumentNullException(nameof(options)); base.EvaluateChildElementChanges(match, options, aggregator); RunComparisonStep(EvaluateFieldChanges, match, options, aggregator); }
protected override void EvaluateModifierChanges(ItemMatch <IMethodDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { match = match ?? throw new ArgumentNullException(nameof(match)); options = options ?? throw new ArgumentNullException(nameof(options)); base.EvaluateModifierChanges(match, options, aggregator); RunComparisonStep(EvaluateMethodModifierChanges, match, options, aggregator, true); }
private void EvaluateMethodModifierChanges( ItemMatch <IMethodDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var convertedMatch = new ItemMatch <IModifiersElement <MethodModifiers> >(match.OldItem, match.NewItem); var results = _methodModifiersComparer.CompareMatch(convertedMatch, options); aggregator.AddResults(results); }
private void EvaluateGenericTypeDefinitionChanges( ItemMatch <IMethodDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var convertedMatch = new ItemMatch <IGenericTypeElement>(match.OldItem, match.NewItem); var results = _genericTypeElementComparer.CompareMatch(convertedMatch, options); aggregator.AddResults(results); }
private void EvaluateAccessModifierChanges( ItemMatch <IPropertyAccessorDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var convertedMatch = new ItemMatch <IAccessModifiersElement <PropertyAccessorAccessModifiers> >(match.OldItem, match.NewItem); var results = _propertyAccessorAccessModifiersComparer.CompareMatch(convertedMatch, options); aggregator.AddResults(results); }
private static void EvaluateNamedArgument(ItemMatch <IAttributeDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldArguments = match.OldItem.Arguments.Where(x => x.ArgumentType == ArgumentType.Named).ToList(); var newArguments = match.NewItem.Arguments.Where(x => x.ArgumentType == ArgumentType.Named).ToList(); // At this point we have the same number of named arguments // Assuming there is a change, it can either be // All parameter names match but a value has changed, or // There is a different in parameter names which can only mean at least one has changed (old removed, new added) // The later will just be recorded as the old named parameter has been removed for (var index = 0; index < oldArguments.Count; index++) { var oldArgument = oldArguments[index]; var newArgument = newArguments.FirstOrDefault(x => x.ParameterName == oldArgument.ParameterName); if (newArgument == null) { // This argument has been removed var args = new FormatArguments( "{DefinitionType} {Identifier} has been removed", oldArgument.ParameterName, null, null); var message = options.MessageFormatter.FormatItemRemovedMessage(oldArgument, args); var result = new ComparisonResult(SemVerChangeType.Breaking, oldArgument, null, message); aggregator.AddResult(result); return; } if (oldArgument.Value != newArgument.Value) { // There is a match on the parameter names but the value has changed var args = new FormatArguments( "{DefinitionType} {Identifier} has changed value from {OldValue} to {NewValue}", oldArgument.ParameterName, oldArgument.Value, newArgument.Value); // Create a match for the arguments var argumentMatch = new ItemMatch <IArgumentDefinition>(oldArgument, newArgument); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, argumentMatch, options.MessageFormatter, args); return; } } }
private void EvaluateParameterChanges( ItemMatch <IMethodDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldParameters = match.OldItem.Parameters.FastToList(); var newParameters = match.NewItem.Parameters.FastToList(); if (oldParameters.Count == 0 && newParameters.Count == 0) { return; } var parameterShift = oldParameters.Count - newParameters.Count; if (parameterShift != 0) { var changeLabel = parameterShift > 0 ? "removed" : "added"; var shiftAmount = Math.Abs(parameterShift); // One or more generic type parameters have been added or removed var suffix = shiftAmount == 1 ? "" : "s"; var args = new FormatArguments( $"{{DefinitionType}} {{Identifier}} has {changeLabel} {shiftAmount} parameter{suffix}", match.NewItem.FullName, null, null); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); // No need to look into how the generic type has changed return; } // We have the same number of parameters, compare them for (var index = 0; index < oldParameters.Count; index++) { var oldParameter = oldParameters[index]; var newParameter = newParameters[index]; var parameterMatch = new ItemMatch <IParameterDefinition>(oldParameter, newParameter); var parameterChanges = _parameterComparer.CompareMatch(parameterMatch, options); aggregator.AddResults(parameterChanges); } }
private static void EvaluateReturnTypeChanges(ItemMatch <T> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldType = match.OldItem.ReturnType; var newType = match.NewItem.ReturnType; IGenericTypeElement deepestNewGenericTypeElement; IGenericTypeElement deepestOldGenericTypeElement; // We need to check whether the element itself can declare generic type parameters // If not, the declaring type will be used for generic type parameter mapping if (match.OldItem is IGenericTypeElement oldElement && match.NewItem is IGenericTypeElement newElement) { deepestOldGenericTypeElement = oldElement; deepestNewGenericTypeElement = newElement; }
private static void EvaluateMethodNameChanges( ItemMatch <IMethodDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { if (match.OldItem.RawName == match.NewItem.RawName) { return; } var args = new FormatArguments( "{DefinitionType} {Identifier} has been renamed to {NewValue}", match.OldItem.FullName, null, match.NewItem.Name); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); }
public static void AddElementChangedResult <T>(this IChangeResultAggregator aggregator, SemVerChangeType changeType, ItemMatch <T> match, IMessageFormatter messageFormatter, FormatArguments arguments) where T : IItemDefinition { aggregator = aggregator ?? throw new ArgumentNullException(nameof(aggregator)); match = match ?? throw new ArgumentNullException(nameof(match)); messageFormatter = messageFormatter ?? throw new ArgumentNullException(nameof(messageFormatter)); arguments = arguments ?? throw new ArgumentNullException(nameof(arguments)); var message = messageFormatter.FormatItemChangedMessage(match, arguments); var result = new ComparisonResult( changeType, match.OldItem, match.NewItem, message); aggregator.AddResult(result); }
private static void EvaluateParameterTypeChanges( ItemMatch <IParameterDefinition> match, ComparerOptions options, IChangeResultAggregator aggregator) { var oldType = match.OldItem.Type; var newType = match.NewItem.Type; var oldMappedType = match.OldItem.DeclaringMethod.GetMatchingGenericType(oldType, match.NewItem.DeclaringMethod); if (oldMappedType != newType) { var args = new FormatArguments( "{DefinitionType} {Identifier} has change type from {OldValue} to {NewValue}", match.NewItem.FullName, oldType, newType); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); } }
protected override void EvaluateTypeDefinitionChanges(ItemMatch <T> match, ComparerOptions options, IChangeResultAggregator aggregator) { base.EvaluateTypeDefinitionChanges(match, options, aggregator); if (_matchResult != null) { aggregator.AddResult(_matchResult); } }
private static void EvaluateGenericConstraints( ItemMatch <IGenericTypeElement> match, IConstraintListDefinition?oldConstraintList, IConstraintListDefinition?newConstraintList, ComparerOptions options, IChangeResultAggregator aggregator) { var oldConstraintCount = oldConstraintList?.Constraints.Count ?? 0; var newConstraintCount = newConstraintList?.Constraints.Count ?? 0; if (oldConstraintCount == 0 && newConstraintCount == 0) { // There are no generic constraints defined on either type return; } if (oldConstraintCount == 0) { var suffix = string.Empty; if (newConstraintCount != 1) { // There is more than one modifier suffix = "s"; } var args = new FormatArguments( $"{{DefinitionType}} {{Identifier}} has added {newConstraintCount} generic type constraint{suffix}", match.NewItem.FullName, null, null); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); // No need to look into the constraints themselves return; } if (newConstraintCount == 0) { var suffix = string.Empty; if (oldConstraintCount != 1) { // There is more than one modifier suffix = "s"; } var args = new FormatArguments( $"{{DefinitionType}} {{Identifier}} has removed {oldConstraintCount} generic type constraint{suffix}", match.NewItem.FullName, null, null); aggregator.AddElementChangedResult(SemVerChangeType.Feature, match, options.MessageFormatter, args); // No need to look into the constraints themselves return; } // Find the old constraints that have been removed var removedConstraints = oldConstraintList !.Constraints.Except(newConstraintList !.Constraints); foreach (var constraint in removedConstraints) { var args = new FormatArguments( "{DefinitionType} {Identifier} has removed the {OldValue} generic type constraint", match.NewItem.FullName, constraint, null); aggregator.AddElementChangedResult(SemVerChangeType.Feature, match, options.MessageFormatter, args); } // Find the new constraints that have been added var addedConstraints = newConstraintList !.Constraints.Except(oldConstraintList !.Constraints); foreach (var constraint in addedConstraints) { var args = new FormatArguments( "{DefinitionType} {Identifier} has added the {NewValue} generic type constraint", match.NewItem.FullName, null, constraint); aggregator.AddElementChangedResult(SemVerChangeType.Breaking, match, options.MessageFormatter, args); } }