Пример #1
0
        private static async Task <Document> SortByValueAsync(
            Document document,
            EnumDeclarationSyntax enumDeclaration,
            ImmutableArray <EnumMemberDeclarationSyntax> selectedMembers,
            CancellationToken cancellationToken)
        {
            SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members;

            int firstIndex = members.IndexOf(selectedMembers[0]);
            int lastIndex  = members.IndexOf(selectedMembers[selectedMembers.Length - 1]);

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var comparer = new EnumMemberDeclarationValueComparer(semanticModel, cancellationToken);

            IEnumerable <EnumMemberDeclarationSyntax> sorted = selectedMembers.OrderBy(f => f, comparer);

            SeparatedSyntaxList <EnumMemberDeclarationSyntax> newMembers = members
                                                                           .Take(firstIndex)
                                                                           .Concat(sorted)
                                                                           .Concat(members.Skip(lastIndex + 1))
                                                                           .ToSeparatedSyntaxList();

            MemberDeclarationSyntax newNode = enumDeclaration.WithMembers(newMembers);

            return(await document.ReplaceNodeAsync(enumDeclaration, newNode, cancellationToken).ConfigureAwait(false));
        }
Пример #2
0
        private static bool IsDuplicateConstraint(TypeParameterConstraintSyntax constraint, SeparatedSyntaxList <TypeParameterConstraintSyntax> constraints)
        {
            int index = constraints.IndexOf(constraint);

            SyntaxKind kind = constraint.Kind();

            switch (kind)
            {
            case SyntaxKind.ClassConstraint:
            case SyntaxKind.StructConstraint:
            {
                for (int i = 0; i < index; i++)
                {
                    if (constraints[i].Kind() == kind)
                    {
                        return(true);
                    }
                }

                break;
            }
            }

            return(false);
        }
        private static async Task <Document> RefactorAsync(
            Document document,
            ArgumentSyntax argument,
            ArgumentListSyntax argumentList,
            CancellationToken cancellationToken)
        {
            SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken);

            SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments;

            int index = arguments.IndexOf(argument);

            ArgumentSyntax nextArgument = arguments[index + 1]
                                          .WithTriviaFrom(argument);

            arguments = arguments
                        .Replace(argument, nextArgument);

            arguments = arguments
                        .Replace(arguments[index + 1], argument.WithTriviaFrom(nextArgument));

            ArgumentListSyntax newNode = argumentList.WithArguments(arguments);

            SyntaxNode newRoot = oldRoot.ReplaceNode(argumentList, newNode);

            return(document.WithSyntaxRoot(newRoot));
        }
Пример #4
0
            static int FindMissingCommaPosition <TNode>(SeparatedSyntaxList <TNode> nodes, TNode node) where TNode : SyntaxNode
            {
                int index = nodes.IndexOf(node);

                Debug.Assert(index > 0);

                if (index <= 0)
                {
                    return(-1);
                }

                if (nodes.GetSeparator(index - 1).IsMissing)
                {
                    return(nodes[index - 1].Span.End);
                }
                else
                {
                    Debug.Assert(index < nodes.Count - 1);

                    if (index == nodes.Count - 1)
                    {
                        return(-1);
                    }

                    Debug.Assert(nodes.GetSeparator(index).IsMissing);

                    if (!nodes.GetSeparator(index).IsMissing)
                    {
                        return(-1);
                    }

                    return(node.Span.End);
                }
            }
        private async Task <Document> FixAsync(
            Document invocationDocument,
            IMethodSymbol method,
            TArgumentSyntax argument,
            SeparatedSyntaxList <TArgumentSyntax> argumentList,
            CancellationToken cancellationToken)
        {
            var methodDeclaration = await method.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

            var(parameterSymbol, isNamedArgument) = await CreateParameterSymbolAsync(
                invocationDocument, method, argument, cancellationToken).ConfigureAwait(false);

            var methodDocument        = invocationDocument.Project.Solution.GetDocument(methodDeclaration.SyntaxTree);
            var syntaxFacts           = methodDocument.GetLanguageService <ISyntaxFactsService>();
            var methodDeclarationRoot = methodDeclaration.SyntaxTree.GetRoot(cancellationToken);
            var editor = new SyntaxEditor(methodDeclarationRoot, methodDocument.Project.Solution.Workspace);

            var parameterDeclaration = editor.Generator.ParameterDeclaration(parameterSymbol)
                                       .WithAdditionalAnnotations(Formatter.Annotation);

            var existingParameters = editor.Generator.GetParameters(methodDeclaration);
            var insertionIndex     = isNamedArgument
                ? existingParameters.Count
                : argumentList.IndexOf(argument);

            AddParameter(
                syntaxFacts, editor, methodDeclaration, argument,
                insertionIndex, parameterDeclaration, cancellationToken);

            var newRoot     = editor.GetChangedRoot();
            var newDocument = methodDocument.WithSyntaxRoot(newRoot);

            return(newDocument);
        }
        public bool TryGetSymbol(TArgumentSyntax argument, out IParameterSymbol parameter)
        {
            parameter = null;

            if (!argumentList.Contains(argument) ||
                MethodSymbol == null ||
                MethodSymbol.IsVararg)
            {
                return(false);
            }

            var nameColonArgumentIdenfitier = GetNameColonArgumentIdentifier(argument);

            if (nameColonArgumentIdenfitier != null)
            {
                parameter = MethodSymbol.Parameters
                            .FirstOrDefault(symbol => symbol.Name == nameColonArgumentIdenfitier.Value.ValueText);
                return(parameter != null);
            }

            var argumentIndex  = argumentList.IndexOf(argument);
            var parameterIndex = argumentIndex;

            if (parameterIndex >= MethodSymbol.Parameters.Length)
            {
                var lastParameter = MethodSymbol.Parameters.Last();
                parameter = lastParameter.IsParams ? lastParameter : null;
                return(parameter != null);
            }
            parameter = MethodSymbol.Parameters[parameterIndex];
            return(true);
        }
Пример #7
0
        private static async Task <Solution> FixAsync(
            Document invocationDocument,
            IMethodSymbol method,
            TArgumentSyntax argument,
            SeparatedSyntaxList <TArgumentSyntax> argumentList,
            bool fixAllReferences,
            CancellationToken cancellationToken)
        {
            var(argumentType, refKind) = await GetArgumentTypeAndRefKindAsync(invocationDocument, argument, cancellationToken).ConfigureAwait(false);

            // The argumentNameSuggestion is the base for the parameter name.
            // For each method declaration the name is made unique to avoid name collisions.
            var(argumentNameSuggestion, isNamedArgument) = await GetNameSuggestionForArgumentAsync(
                invocationDocument, argument, cancellationToken).ConfigureAwait(false);

            var newParameterIndex = isNamedArgument ? (int?)null : argumentList.IndexOf(argument);

            return(await AddParameterService.Instance.AddParameterAsync(
                       invocationDocument,
                       method,
                       argumentType,
                       refKind,
                       argumentNameSuggestion,
                       newParameterIndex,
                       fixAllReferences,
                       cancellationToken).ConfigureAwait(false));
        }
        private static async Task <Document> RefactorAsync(
            Document document,
            ParameterSyntax parameter,
            ParameterListSyntax parameterList,
            CancellationToken cancellationToken)
        {
            SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken);

            SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters;

            int index = parameters.IndexOf(parameter);

            ParameterSyntax nextParameter = parameters[index + 1]
                                            .WithTriviaFrom(parameter);

            parameters = parameters
                         .Replace(parameter, nextParameter);

            parameters = parameters
                         .Replace(parameters[index + 1], parameter.WithTriviaFrom(nextParameter));

            ParameterListSyntax newNode = parameterList.WithParameters(parameters);

            SyntaxNode newRoot = oldRoot.ReplaceNode(parameterList, newNode);

            return(document.WithSyntaxRoot(newRoot));
        }
            > GetArgumentInsertPositionForMethodCandidates(
            TArgumentSyntax argumentOpt,
            SemanticModel semanticModel,
            ISyntaxFactsService syntaxFacts,
            SeparatedSyntaxList <TArgumentSyntax> arguments,
            ImmutableArray <IMethodSymbol> methodCandidates
            )
        {
            var comparer = syntaxFacts.StringComparer;
            var methodsAndArgumentToAdd = ArrayBuilder <
                ArgumentInsertPositionData <TArgumentSyntax>
                > .GetInstance();

            foreach (var method in methodCandidates.OrderBy(m => m.Parameters.Length))
            {
                if (method.IsNonImplicitAndFromSource())
                {
                    var isNamedArgument = !string.IsNullOrWhiteSpace(
                        syntaxFacts.GetNameForArgument(argumentOpt)
                        );

                    if (isNamedArgument || NonParamsParameterCount(method) < arguments.Count)
                    {
                        var argumentToAdd = DetermineFirstArgumentToAdd(
                            semanticModel,
                            syntaxFacts,
                            comparer,
                            method,
                            arguments
                            );

                        if (argumentToAdd != null)
                        {
                            if (argumentOpt != null && argumentToAdd != argumentOpt)
                            {
                                // We were trying to fix a specific argument, but the argument we want
                                // to fix is something different.  That means there was an error earlier
                                // than this argument.  Which means we're looking at a non-viable
                                // constructor or method.  Skip this one.
                                continue;
                            }

                            methodsAndArgumentToAdd.Add(
                                new ArgumentInsertPositionData <TArgumentSyntax>(
                                    method,
                                    argumentToAdd,
                                    arguments.IndexOf(argumentToAdd)
                                    )
                                );
                        }
                    }
                }
            }

            return(methodsAndArgumentToAdd.ToImmutableAndFree());
        }
Пример #10
0
        private static Task <Document> SortByNameAsync(
            Document document,
            EnumDeclarationSyntax enumDeclaration,
            ImmutableArray <EnumMemberDeclarationSyntax> selectedMembers,
            CancellationToken cancellationToken)
        {
            SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members;

            int firstIndex = members.IndexOf(selectedMembers[0]);
            int lastIndex  = members.IndexOf(selectedMembers[selectedMembers.Length - 1]);

            SeparatedSyntaxList <EnumMemberDeclarationSyntax> newMembers = members
                                                                           .Take(firstIndex)
                                                                           .Concat(selectedMembers.OrderBy(f => f, EnumMemberDeclarationNameComparer.Instance))
                                                                           .Concat(members.Skip(lastIndex + 1))
                                                                           .ToSeparatedSyntaxList();

            MemberDeclarationSyntax newNode = enumDeclaration.WithMembers(newMembers);

            return(document.ReplaceNodeAsync(enumDeclaration, newNode, cancellationToken));
        }
        private static object GetFlagsValue(EnumMemberDeclarationSyntax enumMember, INamedTypeSymbol enumSymbol, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var enumDeclaration = (EnumDeclarationSyntax)enumMember.Parent;

            object[]    values      = GetExplicitValues(enumDeclaration, semanticModel, cancellationToken).ToArray();
            SpecialType specialType = enumSymbol.EnumUnderlyingType.SpecialType;

            Optional <object> optional = FlagsUtility.GetUniquePowerOfTwo(
                specialType,
                values,
                startFromHighestExistingValue: false);

            Debug.Assert(optional.HasValue, "");

            if (optional.HasValue)
            {
                object value = optional.Value;

                SeparatedSyntaxList <EnumMemberDeclarationSyntax> members = enumDeclaration.Members;
                int index = members.IndexOf(enumMember);
                int count = members.Take(index).Count(f => HasImplicitValue(f, semanticModel, cancellationToken));

                switch (specialType)
                {
                case SpecialType.System_SByte:
                    return(GetUniquePowerOfTwo((sbyte)value, count, values.Cast <sbyte>().ToArray()));

                case SpecialType.System_Byte:
                    return(GetUniquePowerOfTwo((byte)value, count, values.Cast <byte>().ToArray()));

                case SpecialType.System_Int16:
                    return(GetUniquePowerOfTwo((short)value, count, values.Cast <short>().ToArray()));

                case SpecialType.System_UInt16:
                    return(GetUniquePowerOfTwo((ushort)value, count, values.Cast <ushort>().ToArray()));

                case SpecialType.System_Int32:
                    return(GetUniquePowerOfTwo((int)value, count, values.Cast <int>().ToArray()));

                case SpecialType.System_UInt32:
                    return(GetUniquePowerOfTwo((uint)value, count, values.Cast <uint>().ToArray()));

                case SpecialType.System_Int64:
                    return(GetUniquePowerOfTwo((long)value, count, values.Cast <long>().ToArray()));

                case SpecialType.System_UInt64:
                    return(GetUniquePowerOfTwo((ulong)value, count, values.Cast <ulong>().ToArray()));
                }
            }

            return(null);
        }
Пример #12
0
        public static int FindIndexBeforeFirstOptionalParam(SeparatedSyntaxList <ParameterSyntax> parameters)
        {
            var lastIndex = parameters.Count;

            var firstOptionalParamIndex = parameters.IndexOf(param =>
            {
                var isOptionalParam = param.Default != null;

                return(isOptionalParam);
            });
            var hasOptionalParam = firstOptionalParamIndex == -1;

            var index = hasOptionalParam
                ? lastIndex
                : firstOptionalParamIndex;

            return(index);
        }
        public static async Task ComputeRefactoringAsync(RefactoringContext context, EnumDeclarationSyntax enumDeclaration)
        {
            EnumMemberDeclarationSyntax[] selectedMembers = GetSelectedMembers(enumDeclaration, context.Span).ToArray();

            if (selectedMembers.Length > 1)
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol enumSymbol = semanticModel.GetDeclaredSymbol(enumDeclaration, context.CancellationToken);

                if (enumSymbol != null &&
                    SymbolUtility.IsEnumWithFlagsAttribute(enumSymbol, semanticModel))
                {
                    IFieldSymbol[] fieldSymbols = selectedMembers
                                                  .Select(f => semanticModel.GetDeclaredSymbol(f, context.CancellationToken))
                                                  .ToArray();

                    object[] constantValues = fieldSymbols
                                              .Where(f => f.HasConstantValue)
                                              .Select(f => f.ConstantValue)
                                              .ToArray();

                    object combinedValue = GetCombinedValue(constantValues, enumSymbol);

                    if (combinedValue != null &&
                        !EnumHelper.IsValueDefined(enumSymbol, combinedValue))
                    {
                        SeparatedSyntaxList <EnumMemberDeclarationSyntax> enumMembers = enumDeclaration.Members;

                        string name = Identifier.EnsureUniqueEnumMemberName(
                            enumSymbol,
                            string.Concat(selectedMembers.Select(f => f.Identifier.ValueText)));

                        EnumMemberDeclarationSyntax newEnumMember = CreateEnumMember(name, selectedMembers);

                        int insertIndex = enumMembers.IndexOf(selectedMembers.Last()) + 1;

                        context.RegisterRefactoring(
                            $"Generate enum member '{name}'",
                            cancellationToken => RefactorAsync(context.Document, enumDeclaration, newEnumMember, insertIndex, cancellationToken));
                    }
                }
            }
        }
Пример #14
0
        private static SyntaxNode GetNewMethodDeclaration(
            IMethodSymbol method,
            TArgumentSyntax argument,
            SeparatedSyntaxList <TArgumentSyntax> argumentList,
            SyntaxGenerator generator,
            SyntaxNode declaration,
            ISemanticFactsService semanticFacts,
            string argumentName,
            SyntaxNode expression,
            SemanticModel semanticModel,
            ITypeSymbol parameterType,
            CancellationToken cancellationToken)
        {
            if (!string.IsNullOrWhiteSpace(argumentName))
            {
                var newParameterSymbol = CodeGenerationSymbolFactory.CreateParameterSymbol(
                    attributes: default(ImmutableArray <AttributeData>),
                    refKind: RefKind.None,
                    isParams: false,
                    type: parameterType,
                    name: argumentName);

                var newParameterDeclaration = generator.ParameterDeclaration(newParameterSymbol);
                return(generator.AddParameters(declaration, new[] { newParameterDeclaration }));
            }
            else
            {
                var name = semanticFacts.GenerateNameForExpression(
                    semanticModel, expression, capitalize: false, cancellationToken: cancellationToken);
                var uniqueName = NameGenerator.EnsureUniqueness(name, method.Parameters.Select(p => p.Name));

                var newParameterSymbol = CodeGenerationSymbolFactory.CreateParameterSymbol(
                    attributes: default(ImmutableArray <AttributeData>),
                    refKind: RefKind.None,
                    isParams: false,
                    type: parameterType,
                    name: uniqueName);

                var argumentIndex           = argumentList.IndexOf(argument);
                var newParameterDeclaration = generator.ParameterDeclaration(newParameterSymbol);
                return(generator.InsertParameters(
                           declaration, argumentIndex, new[] { newParameterDeclaration }));
            }
        }
Пример #15
0
        internal static IParameterSymbol DetermineParameter(
            ArgumentSyntax argument,
            SeparatedSyntaxList <ArgumentSyntax> arguments,
            ImmutableArray <IParameterSymbol> parameters,
            bool allowParams = false)
        {
            string name = argument.NameColon?.Name?.Identifier.ValueText;

            if (name != null)
            {
                foreach (IParameterSymbol parameter in parameters)
                {
                    if (parameter.Name == name)
                    {
                        return(parameter);
                    }
                }

                return(null);
            }

            int index = arguments.IndexOf(argument);

            if (index >= 0)
            {
                if (index < parameters.Length)
                {
                    return(parameters[index]);
                }

                if (allowParams)
                {
                    IParameterSymbol lastParameter = parameters.LastOrDefault();

                    if (lastParameter?.IsParams == true)
                    {
                        return(lastParameter);
                    }
                }
            }

            return(null);
        }
Пример #16
0
        private void DoTestAddInsertRemoveOnEmptyList(SeparatedSyntaxList <SyntaxNode> list)
        {
            Assert.Equal(0, list.Count);

            SyntaxNode nodeD = SyntaxFactory.ParseExpression("D");
            SyntaxNode nodeE = SyntaxFactory.ParseExpression("E");

            var newList = list.Add(nodeD);

            Assert.Equal(1, newList.Count);
            Assert.Equal("D", newList.ToFullString());

            newList = list.AddRange(new[] { nodeD, nodeE });
            Assert.Equal(2, newList.Count);
            Assert.Equal("D,E", newList.ToFullString());

            newList = list.Insert(0, nodeD);
            Assert.Equal(1, newList.Count);
            Assert.Equal("D", newList.ToFullString());

            newList = list.InsertRange(0, new[] { nodeD, nodeE });
            Assert.Equal(2, newList.Count);
            Assert.Equal("D,E", newList.ToFullString());

            newList = list.Remove(nodeD);
            Assert.Equal(0, newList.Count);

            Assert.Equal(-1, list.IndexOf(nodeD));
            Assert.Throws <ArgumentOutOfRangeException>(() => list.RemoveAt(0));
            Assert.Throws <ArgumentOutOfRangeException>(() => list.Insert(1, nodeD));
            Assert.Throws <ArgumentOutOfRangeException>(() => list.Insert(-1, nodeD));
            Assert.Throws <ArgumentOutOfRangeException>(() => list.InsertRange(1, new[] { nodeD }));
            Assert.Throws <ArgumentOutOfRangeException>(() => list.InsertRange(-1, new[] { nodeD }));
            Assert.Throws <ArgumentNullException>(() => list.Add(null));
            Assert.Throws <ArgumentNullException>(
                () => list.AddRange((IEnumerable <SyntaxNode>)null)
                );
            Assert.Throws <ArgumentNullException>(() => list.Insert(0, null));
            Assert.Throws <ArgumentNullException>(
                () => list.InsertRange(0, (IEnumerable <SyntaxNode>)null)
                );
        }
Пример #17
0
        private static AttributeArgumentSyntax GetArgument(RefactoringContext context, AttributeArgumentListSyntax argumentList)
        {
            SeparatedSyntaxList <AttributeArgumentSyntax> arguments = argumentList.Arguments;

            foreach (AttributeArgumentSyntax argument in arguments)
            {
                if (argument.IsMissing &&
                    context.Span.Contains(argument.Span))
                {
                    int index = arguments.IndexOf(argument);

                    if (index > 0 &&
                        !arguments[index - 1].IsMissing)
                    {
                        return(argument);
                    }
                }
            }

            return(null);
        }
        private static async Task <Document> OrderNamedArgumentsAsync(
            Document document,
            BaseArgumentListSyntax argumentList,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            ImmutableArray <IParameterSymbol> parameters = semanticModel
                                                           .GetSymbol(argumentList.Parent, cancellationToken)
                                                           .ParametersOrDefault();

            SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments;

            int firstIndex = OrderNamedArgumentsAnalyzer.IndexOfFirstFixableParameter(argumentList, arguments, semanticModel, cancellationToken);

            SeparatedSyntaxList <ArgumentSyntax> newArguments = arguments;

            for (int i = firstIndex; i < arguments.Count; i++)
            {
                IParameterSymbol parameter = parameters[i];

                int index = arguments.IndexOf(f => f.NameColon?.Name.Identifier.ValueText == parameter.Name);

                Debug.Assert(index != -1, parameter.Name);

                if (index != -1 &&
                    index != i)
                {
                    newArguments = newArguments.ReplaceAt(i, arguments[index]);
                }
            }

            BaseArgumentListSyntax newNode = argumentList
                                             .WithArguments(newArguments)
                                             .WithFormatterAnnotation();

            return(await document.ReplaceNodeAsync(argumentList, newNode, cancellationToken).ConfigureAwait(false));
        }
Пример #19
0
            public override SeparatedSyntaxList <TNode> VisitList <TNode>(SeparatedSyntaxList <TNode> list)
            {
                if (_originalNode is TNode node)
                {
                    var index = list.IndexOf(node);
                    if (index >= 0 && index < list.Count)
                    {
                        switch (editKind)
                        {
                        case ListEditKind.Replace:
                            return(list.ReplaceRange(node, _newNodes.Cast <TNode>()));

                        case ListEditKind.InsertAfter:
                            return(list.InsertRange(index + 1, _newNodes.Cast <TNode>()));

                        case ListEditKind.InsertBefore:
                            return(list.InsertRange(index, _newNodes.Cast <TNode>()));
                        }
                    }
                }

                return(base.VisitList(list));
            }
Пример #20
0
        private static ParameterSyntax GetParameter(CodeRefactoringContext context, ParameterListSyntax parameterList)
        {
            if (context.Span.IsEmpty)
            {
                SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters;

                foreach (ParameterSyntax parameter in parameters)
                {
                    if (parameter.IsMissing &&
                        context.Span.Contains(parameter.Span))
                    {
                        int index = parameters.IndexOf(parameter);

                        if (index > 0 &&
                            !parameters[index - 1].IsMissing)
                        {
                            return(parameter);
                        }
                    }
                }
            }

            return(null);
        }
Пример #21
0
 /// <summary>
 /// True if the list has at least one node of the specified kind.
 /// </summary>
 public static bool Any <TNode>(this SeparatedSyntaxList <TNode> list, int kind)
     where TNode : SyntaxNode
 {
     return(list.IndexOf(kind) >= 0);
 }
Пример #22
0
 public static bool IsFirst <TNode>(this SeparatedSyntaxList <TNode> list, TNode node) where TNode : SyntaxNode
 {
     return(list.IndexOf(node) == 0);
 }
Пример #23
0
 public static bool IsLast <TNode>(this SeparatedSyntaxList <TNode> list, TNode node) where TNode : SyntaxNode
 {
     return(list.Any() &&
            list.IndexOf(node) == list.Count - 1);
 }
Пример #24
0
        private async Task <Solution> FixAsync(
            Document invocationDocument,
            IMethodSymbol method,
            TArgumentSyntax argument,
            SeparatedSyntaxList <TArgumentSyntax> argumentList,
            bool fixAllReferences,
            CancellationToken cancellationToken)
        {
            var solution = invocationDocument.Project.Solution;

            var(argumentType, refKind) = await GetArgumentTypeAndRefKindAsync(invocationDocument, argument, cancellationToken).ConfigureAwait(false);

            // The argumentNameSuggestion is the base for the parameter name.
            // For each method declaration the name is made unique to avoid name collisions.
            var(argumentNameSuggestion, isNamedArgument) = await GetNameSuggestionForArgumentAsync(
                invocationDocument, argument, cancellationToken).ConfigureAwait(false);

            var referencedSymbols = fixAllReferences
                ? await FindMethodDeclarationReferences(invocationDocument, method, cancellationToken).ConfigureAwait(false)
                : method.GetAllMethodSymbolsOfPartialParts();

            var anySymbolReferencesNotInSource = referencedSymbols.Any(symbol => !symbol.IsFromSource());
            var locationsInSource = referencedSymbols.Where(symbol => symbol.IsFromSource());

            // Indexing Locations[0] is valid because IMethodSymbols have one location at most
            // and IsFromSource() tests if there is at least one location.
            var locationsByDocument = locationsInSource.ToLookup(declarationLocation
                                                                 => solution.GetDocument(declarationLocation.Locations[0].SourceTree));

            foreach (var documentLookup in locationsByDocument)
            {
                var document    = documentLookup.Key;
                var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();
                var syntaxRoot  = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                var editor    = new SyntaxEditor(syntaxRoot, solution.Workspace);
                var generator = editor.Generator;
                foreach (var methodDeclaration in documentLookup)
                {
                    var methodNode         = syntaxRoot.FindNode(methodDeclaration.Locations[0].SourceSpan);
                    var existingParameters = generator.GetParameters(methodNode);
                    var insertionIndex     = isNamedArgument
                        ? existingParameters.Count
                        : argumentList.IndexOf(argument);

                    // if the preceding parameter is optional, the new parameter must also be optional
                    // see also BC30202 and CS1737
                    var parameterMustBeOptional = insertionIndex > 0 &&
                                                  syntaxFacts.GetDefaultOfParameter(existingParameters[insertionIndex - 1]) != null;

                    var parameterSymbol = CreateParameterSymbol(
                        methodDeclaration, argumentType, refKind, parameterMustBeOptional, argumentNameSuggestion);

                    var argumentInitializer  = parameterMustBeOptional ? generator.DefaultExpression(argumentType) : null;
                    var parameterDeclaration = generator.ParameterDeclaration(parameterSymbol, argumentInitializer)
                                               .WithAdditionalAnnotations(Formatter.Annotation);
                    if (anySymbolReferencesNotInSource && methodDeclaration == method)
                    {
                        parameterDeclaration = parameterDeclaration.WithAdditionalAnnotations(
                            ConflictAnnotation.Create(FeaturesResources.Related_method_signatures_found_in_metadata_will_not_be_updated));
                    }


                    if (method.MethodKind == MethodKind.ReducedExtension)
                    {
                        insertionIndex++;
                    }

                    AddParameter(
                        syntaxFacts, editor, methodNode, argument,
                        insertionIndex, parameterDeclaration, cancellationToken);
                }

                var newRoot = editor.GetChangedRoot();
                solution = solution.WithDocumentSyntaxRoot(document.Id, newRoot);
            }

            return(solution);
        }
Пример #25
0
 private static int IndexOf(ArgumentSyntax argument, SeparatedSyntaxList <ParameterSyntax> arguments)
 {
     return(arguments.IndexOf(x => x.Identifier.ValueText == ((IdentifierNameSyntax)argument.Expression).Identifier.ValueText));
 }
Пример #26
0
 public static bool Contains <TNode>(this SeparatedSyntaxList <TNode> list, SyntaxKind kind) where TNode : SyntaxNode
 {
     return(list.IndexOf(kind) != -1);
 }
Пример #27
0
        private static void AnalyzeNamedType(SymbolAnalysisContext context)
        {
            var typeSymbol = (INamedTypeSymbol)context.Symbol;

            if (typeSymbol.IsImplicitlyDeclared)
            {
                return;
            }

            if (typeSymbol.TypeKind != TypeKind.Enum)
            {
                return;
            }

            bool hasFlagsAttribute = typeSymbol.HasAttribute(MetadataNames.System_FlagsAttribute);

            ImmutableArray <ISymbol> members = default;

            if (hasFlagsAttribute &&
                DiagnosticRules.DeclareEnumMemberWithZeroValue.IsEffective(context))
            {
                members = typeSymbol.GetMembers();

                if (!ContainsFieldWithZeroValue(members))
                {
                    var enumDeclaration = (EnumDeclarationSyntax)typeSymbol.GetSyntax(context.CancellationToken);

                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.DeclareEnumMemberWithZeroValue, enumDeclaration.Identifier);
                }
            }

            EnumSymbolInfo enumInfo = default;

            if (hasFlagsAttribute &&
                DiagnosticRules.CompositeEnumValueContainsUndefinedFlag.IsEffective(context))
            {
                enumInfo = EnumSymbolInfo.Create(typeSymbol);

                foreach (EnumFieldSymbolInfo field in enumInfo.Fields)
                {
                    if (field.HasValue &&
                        ConvertHelpers.CanConvertFromUInt64(field.Value, typeSymbol.EnumUnderlyingType.SpecialType) &&
                        !IsMaxValue(field.Value, typeSymbol.EnumUnderlyingType.SpecialType) &&
                        field.HasCompositeValue())
                    {
                        foreach (ulong value in (field.GetFlags()))
                        {
                            if (!enumInfo.Contains(value))
                            {
                                ReportUndefinedFlag(context, field.Symbol, value.ToString());
                            }
                        }
                    }
                }
            }

            if (hasFlagsAttribute &&
                DiagnosticRules.DeclareEnumValueAsCombinationOfNames.IsEffective(context))
            {
                if (members.IsDefault)
                {
                    members = typeSymbol.GetMembers();
                }

                foreach (ISymbol member in members)
                {
                    if (!(member is IFieldSymbol fieldSymbol))
                    {
                        continue;
                    }

                    if (!fieldSymbol.HasConstantValue)
                    {
                        break;
                    }

                    EnumFieldSymbolInfo fieldInfo = EnumFieldSymbolInfo.Create(fieldSymbol);

                    if (!fieldInfo.HasCompositeValue())
                    {
                        continue;
                    }

                    var declaration = (EnumMemberDeclarationSyntax)fieldInfo.Symbol.GetSyntax(context.CancellationToken);

                    ExpressionSyntax expression = declaration.EqualsValue?.Value.WalkDownParentheses();

                    if (expression != null &&
                        (expression.IsKind(SyntaxKind.NumericLiteralExpression) ||
                         expression
                         .DescendantNodes()
                         .Any(f => f.IsKind(SyntaxKind.NumericLiteralExpression))))
                    {
                        if (enumInfo.IsDefault)
                        {
                            enumInfo = EnumSymbolInfo.Create(typeSymbol);

                            if (enumInfo.Fields.Any(f => !f.HasValue))
                            {
                                break;
                            }
                        }

                        List <EnumFieldSymbolInfo> values = enumInfo.Decompose(fieldInfo);

                        if (values?.Count > 1)
                        {
                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.DeclareEnumValueAsCombinationOfNames, expression);
                        }
                    }
                }
            }

            if (hasFlagsAttribute &&
                DiagnosticRules.UseBitShiftOperator.IsEffective(context))
            {
                if (members.IsDefault)
                {
                    members = typeSymbol.GetMembers();
                }

                foreach (ISymbol member in members)
                {
                    if (!(member is IFieldSymbol fieldSymbol))
                    {
                        continue;
                    }

                    if (!fieldSymbol.HasConstantValue)
                    {
                        continue;
                    }

                    EnumFieldSymbolInfo fieldInfo = EnumFieldSymbolInfo.Create(fieldSymbol);

                    if (fieldInfo.Value <= 1)
                    {
                        continue;
                    }

                    if (fieldInfo.HasCompositeValue())
                    {
                        continue;
                    }

                    var declaration = (EnumMemberDeclarationSyntax)fieldInfo.Symbol.GetSyntax(context.CancellationToken);

                    ExpressionSyntax expression = declaration.EqualsValue?.Value.WalkDownParentheses();

                    if (expression.IsKind(SyntaxKind.NumericLiteralExpression))
                    {
                        var enumDeclaration = (EnumDeclarationSyntax)typeSymbol.GetSyntax(context.CancellationToken);

                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseBitShiftOperator, enumDeclaration.Identifier);
                        break;
                    }
                }
            }

            if (DiagnosticRules.DuplicateEnumValue.IsEffective(context))
            {
                if (enumInfo.IsDefault)
                {
                    enumInfo = EnumSymbolInfo.Create(typeSymbol);
                }

                ImmutableArray <EnumFieldSymbolInfo> fields = enumInfo.Fields;

                if (fields.Length > 1)
                {
                    EnumFieldSymbolInfo symbolInfo1 = fields[0];
                    EnumFieldSymbolInfo symbolInfo2 = default;

                    for (int i = 1; i < fields.Length; i++, symbolInfo1 = symbolInfo2)
                    {
                        symbolInfo2 = fields[i];

                        if (!symbolInfo1.HasValue ||
                            !symbolInfo2.HasValue ||
                            symbolInfo1.Value != symbolInfo2.Value)
                        {
                            continue;
                        }

                        var enumMember1 = (EnumMemberDeclarationSyntax)symbolInfo1.Symbol.GetSyntax(context.CancellationToken);

                        if (enumMember1 == null)
                        {
                            continue;
                        }

                        var enumMember2 = (EnumMemberDeclarationSyntax)symbolInfo2.Symbol.GetSyntax(context.CancellationToken);

                        if (enumMember2 == null)
                        {
                            continue;
                        }

                        ExpressionSyntax value1 = enumMember1.EqualsValue?.Value?.WalkDownParentheses();
                        ExpressionSyntax value2 = enumMember2.EqualsValue?.Value?.WalkDownParentheses();

                        if (value1 == null)
                        {
                            if (value2 != null)
                            {
                                ReportDuplicateValue(context, enumMember1, value2);
                            }
                        }
                        else if (value2 == null)
                        {
                            ReportDuplicateValue(context, enumMember2, value1);
                        }
                        else
                        {
                            SyntaxKind kind1 = value1.Kind();
                            SyntaxKind kind2 = value2.Kind();

                            if (kind1 == SyntaxKind.NumericLiteralExpression)
                            {
                                if (kind2 == SyntaxKind.NumericLiteralExpression)
                                {
                                    var enumDeclaration = (EnumDeclarationSyntax)enumMember1.Parent;
                                    SeparatedSyntaxList <EnumMemberDeclarationSyntax> enumMembers = enumDeclaration.Members;

                                    if (enumMembers.IndexOf(enumMember1) < enumMembers.IndexOf(enumMember2))
                                    {
                                        ReportDuplicateValue(context, value2);
                                    }
                                    else
                                    {
                                        ReportDuplicateValue(context, value1);
                                    }
                                }
                                else if (!string.Equals((value2 as IdentifierNameSyntax)?.Identifier.ValueText, enumMember1.Identifier.ValueText, StringComparison.Ordinal))
                                {
                                    ReportDuplicateValue(context, value1);
                                }
                            }
                            else if (kind2 == SyntaxKind.NumericLiteralExpression &&
                                     !string.Equals((value1 as IdentifierNameSyntax)?.Identifier.ValueText, enumMember2.Identifier.ValueText, StringComparison.Ordinal))
                            {
                                ReportDuplicateValue(context, value2);
                            }
                        }
                    }
                }
            }
        }
Пример #28
0
 private static int IndexOf(ParameterSyntax parameter, SeparatedSyntaxList <ArgumentSyntax> arguments)
 {
     return(arguments.IndexOf(x => ((IdentifierNameSyntax)x.Expression).Identifier.ValueText == parameter.Identifier.ValueText));
 }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsEnabled(CodeFixIdentifiers.AddMissingComma))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            ExpressionSyntax expression = root.FindNode(context.Span).FirstAncestorOrSelf <ExpressionSyntax>();

            if (expression == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.SyntaxErrorCharExpected:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.AddMissingComma))
                    {
                        break;
                    }

                    if (!expression.IsParentKind(SyntaxKind.ArrayInitializerExpression))
                    {
                        break;
                    }

                    var initializer = (InitializerExpressionSyntax)expression.Parent;

                    SeparatedSyntaxList <ExpressionSyntax> expressions = initializer.Expressions;

                    int index = expressions.IndexOf(expression);

                    Debug.Assert(index > 0);

                    if (index <= 0)
                    {
                        break;
                    }

                    int newCommaIndex = expression.Span.End;

                    if (expressions.GetSeparator(index - 1).IsMissing)
                    {
                        newCommaIndex = expressions[index - 1].Span.End;
                    }
                    else
                    {
                        Debug.Assert(index < expressions.Count - 1);

                        if (index == expressions.Count - 1)
                        {
                            break;
                        }

                        Debug.Assert(expressions.GetSeparator(index).IsMissing);

                        if (!expressions.GetSeparator(index).IsMissing)
                        {
                            break;
                        }

                        newCommaIndex = expression.Span.End;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Add missing comma",
                        cancellationToken =>
                        {
                            var textChange = new TextChange(new TextSpan(newCommaIndex, 0), ",");
                            return(context.Document.WithTextChangeAsync(textChange, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Пример #30
0
        private void DoTestAddInsertRemoveOnEmptyList(SeparatedSyntaxList<SyntaxNode> list)
        {
            Assert.Equal(0, list.Count);

            SyntaxNode nodeD = SyntaxFactory.ParseExpression("D");
            SyntaxNode nodeE = SyntaxFactory.ParseExpression("E");

            var newList = list.Add(nodeD);
            Assert.Equal(1, newList.Count);
            Assert.Equal("D", newList.ToFullString());

            newList = list.AddRange(new[] { nodeD, nodeE });
            Assert.Equal(2, newList.Count);
            Assert.Equal("D,E", newList.ToFullString());

            newList = list.Insert(0, nodeD);
            Assert.Equal(1, newList.Count);
            Assert.Equal("D", newList.ToFullString());

            newList = list.InsertRange(0, new[] { nodeD, nodeE });
            Assert.Equal(2, newList.Count);
            Assert.Equal("D,E", newList.ToFullString());

            newList = list.Remove(nodeD);
            Assert.Equal(0, newList.Count);

            Assert.Equal(-1, list.IndexOf(nodeD));
            Assert.Throws<ArgumentOutOfRangeException>(() => list.RemoveAt(0));
            Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(1, nodeD));
            Assert.Throws<ArgumentOutOfRangeException>(() => list.Insert(-1, nodeD));
            Assert.Throws<ArgumentOutOfRangeException>(() => list.InsertRange(1, new[] { nodeD }));
            Assert.Throws<ArgumentOutOfRangeException>(() => list.InsertRange(-1, new[] { nodeD }));
            Assert.Throws<ArgumentNullException>(() => list.Add(null));
            Assert.Throws<ArgumentNullException>(() => list.AddRange((IEnumerable<SyntaxNode>)null));
            Assert.Throws<ArgumentNullException>(() => list.Insert(0, null));
            Assert.Throws<ArgumentNullException>(() => list.InsertRange(0, (IEnumerable<SyntaxNode>)null));
        }
Пример #31
0
 public override int IndexOf(TNode node)
 => SyntaxList.IndexOf(SyntaxWrapper.Unwrap(node));