Example #1
0
        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);
            }
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        private void EvaluateFieldChanges(
            ItemMatch <IClassDefinition> match,
            ComparerOptions options,
            IChangeResultAggregator aggregator)
        {
            var changes = _fieldProcessor.CalculateChanges(match.OldItem.Fields, match.NewItem.Fields, options);

            aggregator.AddResults(changes);
        }
Example #6
0
        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);
        }
Example #7
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
        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;
                }
            }
        }
Example #13
0
        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);
            }
        }
Example #14
0
        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;
            }
Example #15
0
        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);
            }
        }