public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var diagnostic = context.Diagnostics.First();
            var serializedNamingStyle = diagnostic.Properties[nameof(NamingStyle)];
            var style = NamingStyle.FromXElement(XElement.Parse(serializedNamingStyle));

            var document = context.Document;
            var span = context.Span;

            var root = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            var node = root.FindNode(span);
            var model = await document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
            var symbol = model.GetDeclaredSymbol(node, context.CancellationToken);

            var fixedNames = style.MakeCompliant(symbol.Name);
            foreach (var fixedName in fixedNames)
            {
                var solution = context.Document.Project.Solution;
                context.RegisterCodeFix(
                    new FixNameCodeAction(
                        string.Format(FeaturesResources.FixNamingViolation, fixedName),
                        async c => await Renamer.RenameSymbolAsync(
                            solution,
                            symbol,
                            fixedName,
                            document.Options,
                            c).ConfigureAwait(false), 
                        nameof(AbstractNamingStyleCodeFixProvider)), 
                    diagnostic);
            }
        }
        public override Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            context.RegisterCodeFix(
                new PreferFrameworkTypeCodeAction(
                    FeaturesResources.Use_framework_type,
                    c => CreateChangedDocumentAsync(context.Document, context.Span, c)),
                context.Diagnostics);

            return SpecializedTasks.EmptyTask;
        }
Esempio n. 3
0
 private void RegisterSuppressionFixes(CodeFixContext context, IEnumerable<CodeFix> suppressionFixes)
 {
     if (suppressionFixes != null)
     {
         foreach (var suppressionFix in suppressionFixes)
         {
             context.RegisterCodeFix(suppressionFix.Action, suppressionFix.Diagnostics);
         }
     }
 }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var diagnostics = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project = document.Project;
            var diagnostic = diagnostics.First();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var node = root.FindToken(span.Start).GetAncestors<SyntaxNode>().First(n => n.Span.Contains(span));

            using (Logger.LogBlock(FunctionId.Refactoring_FullyQualify, cancellationToken))
            {
                // Has to be a simple identifier or generic name.
                if (node == null || !CanFullyQualify(diagnostic, ref node))
                {
                    return;
                }

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

                var matchingTypes = await this.GetMatchingTypesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);
                var matchingNamespaces = await this.GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                if (matchingTypes.IsEmpty && matchingNamespaces.IsEmpty)
                {
                    return;
                }

                var matchingTypeContainers = FilterAndSort(GetContainers(matchingTypes, semanticModel.Compilation));
                var matchingNamespaceContainers = FilterAndSort(GetContainers(matchingNamespaces, semanticModel.Compilation));

                var proposedContainers =
                    matchingTypeContainers.Concat(matchingNamespaceContainers)
                                            .Distinct()
                                            .Take(MaxResults);

                var displayService = project.LanguageServices.GetService<ISymbolDisplayService>();
                var codeActions = CreateActions(context, document, diagnostic, node, semanticModel, proposedContainers, displayService).ToImmutableArray();

                if (codeActions.Length > 1)
                {
                    // Wrap the spell checking actions into a single top level suggestion
                    // so as to not clutter the list.
                    context.RegisterCodeFix(new GroupingCodeAction(
                        string.Format(FeaturesResources.Fully_qualify_0, GetNodeName(document, node)),
                        codeActions), context.Diagnostics);
                }
                else
                {
                    context.RegisterFixes(codeActions, context.Diagnostics);
                }
            }
        }
Esempio n. 5
0
 public async override Task RegisterCodeFixesAsync(CodeFixContext context)
 {
     var diagnostics = context.Diagnostics.WhereAsArray(_suppressionFixProvider.CanBeSuppressedOrUnsuppressed);
     var suppressionFixes = await _suppressionFixProvider.GetSuppressionsAsync(context.Document, context.Span, diagnostics, context.CancellationToken).ConfigureAwait(false);
     if (suppressionFixes != null)
     {
         foreach (var suppressionFix in suppressionFixes)
         {
             context.RegisterCodeFix(suppressionFix.Action, suppressionFix.Diagnostics);
         }
     }
 }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            if (!TryGetNode(root, context.Span, out var node))
            {
                return;
            }

            var diagnostic = context.Diagnostics.FirstOrDefault();

            var codeAction = await GetCodeFixAsync(root, node, context.Document, diagnostic, context.CancellationToken).ConfigureAwait(false);

            if (codeAction != null)
            {
                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
Esempio n. 7
0
        public async override Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var diagnostics = context.Diagnostics.Where(_suppressionFixProvider.CanBeSuppressedOrUnsuppressed);

            var documentDiagnostics = diagnostics.Where(d => d.Location.IsInSource).ToImmutableArray();
            if (!documentDiagnostics.IsEmpty)
            {
                var suppressionFixes = await _suppressionFixProvider.GetSuppressionsAsync(context.Document, context.Span, diagnostics, context.CancellationToken).ConfigureAwait(false);
                RegisterSuppressionFixes(context, suppressionFixes);
            }

            var projectDiagnostics = diagnostics.Where(d => !d.Location.IsInSource).ToImmutableArray();
            if (!projectDiagnostics.IsEmpty)
            {
                var suppressionFixes = await _suppressionFixProvider.GetSuppressionsAsync(context.Project, diagnostics, context.CancellationToken).ConfigureAwait(false);
                RegisterSuppressionFixes(context, suppressionFixes);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            // NOTE(DustinCa): Not supported in REPL for now.
            if (context.Document.SourceCodeKind == SourceCodeKind.Interactive)
            {
                return;
            }

            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            var names = GetTargetNodes(root, context.Span);
            foreach (var name in names)
            {
                var codeActions = await GetCodeActionsAsync(context.Document, name, context.CancellationToken).ConfigureAwait(false);
                if (codeActions == null || codeActions.IsEmpty())
                {
                    continue;
                }

                context.RegisterFixes(codeActions, context.Diagnostics);
                return;
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            // TODO: https://github.com/dotnet/roslyn/issues/5777
            // Not supported in REPL for now.
            if (context.Project.IsSubmission)
            {
                return;
            }

            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            var names = GetTargetNodes(root, context.Span);
            foreach (var name in names)
            {
                var codeActions = await GetCodeActionsAsync(context.Document, name, context.CancellationToken).ConfigureAwait(false);
                if (codeActions == null || codeActions.IsEmpty())
                {
                    continue;
                }

                context.RegisterFixes(codeActions, context.Diagnostics);
                return;
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out EnumDeclarationSyntax enumDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.AddNewLineBeforeEnumMember:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Add new line",
                        cancellationToken => AddNewLineBeforeEnumMemberRefactoring.RefactorAsync(context.Document, enumDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.SortEnumMembers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Sort '{enumDeclaration.Identifier}' members",
                        cancellationToken => SortEnumMembersAsync(context.Document, enumDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.EnumShouldDeclareExplicitValues:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

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

                    EnumSymbolInfo enumInfo = EnumSymbolInfo.Create(enumSymbol);

                    ImmutableArray <ulong> values = enumInfo
                                                    .Fields
                                                    .Where(f => f.HasValue && ((EnumMemberDeclarationSyntax)f.Symbol.GetSyntax(context.CancellationToken)).EqualsValue != null)
                                                    .Select(f => f.Value)
                                                    .ToImmutableArray();

                    Optional <ulong> optional = FlagsUtility <ulong> .Instance.GetUniquePowerOfTwo(values);

                    if (!optional.HasValue ||
                        !ConvertHelpers.CanConvert(optional.Value, enumSymbol.EnumUnderlyingType.SpecialType))
                    {
                        return;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Declare explicit values",
                        ct => DeclareExplicitValueAsync(context.Document, enumDeclaration, enumSymbol, values, semanticModel, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var diagnostics = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project = document.Project;
            var diagnostic = diagnostics.First();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var ancestors = root.FindToken(span.Start, findInsideTrivia: true).GetAncestors<SyntaxNode>();
            if (!ancestors.Any())
            {
                return;
            }

            var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root);
            if (node == null)
            {
                return;
            }

            var placeSystemNamespaceFirst = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Shared.Options.OrganizerOptions.PlaceSystemNamespaceFirst, document.Project.Language);

            using (Logger.LogBlock(FunctionId.Refactoring_AddImport, cancellationToken))
            {
                if (!cancellationToken.IsCancellationRequested)
                {
                    if (this.CanAddImport(node, cancellationToken))
                    {
                        var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
                        var containingType = semanticModel.GetEnclosingNamedType(node.SpanStart, cancellationToken);
                        var containingTypeOrAssembly = containingType ?? (ISymbol)semanticModel.Compilation.Assembly;
                        var namespacesInScope = this.GetNamespacesInScope(semanticModel, node, cancellationToken);
                        var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();

                        var matchingTypesNamespaces = await this.GetNamespacesForMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingTypes = await this.GetMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingNamespaces = await this.GetNamespacesForMatchingNamespacesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingExtensionMethodsNamespaces = await this.GetNamespacesForMatchingExtensionMethodsAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingFieldsAndPropertiesAsync = await this.GetNamespacesForMatchingFieldsAndPropertiesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var queryPatternsNamespaces = await this.GetNamespacesForQueryPatternsAsync(project, diagnostic, node, semanticModel, namespacesInScope, cancellationToken).ConfigureAwait(false);

                        if (matchingTypesNamespaces != null || matchingNamespaces != null || matchingExtensionMethodsNamespaces != null || matchingFieldsAndPropertiesAsync != null || queryPatternsNamespaces != null || matchingTypes != null)
                        {
                            matchingTypesNamespaces = matchingTypesNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingExtensionMethodsNamespaces = matchingExtensionMethodsNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingFieldsAndPropertiesAsync = matchingFieldsAndPropertiesAsync ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            queryPatternsNamespaces = queryPatternsNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingTypes = matchingTypes ?? SpecializedCollections.EmptyList<ITypeSymbol>();

                            var proposedImports =
                                matchingTypesNamespaces.Cast<INamespaceOrTypeSymbol>()
                                           .Concat(matchingNamespaces.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(matchingExtensionMethodsNamespaces.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(matchingFieldsAndPropertiesAsync.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(queryPatternsNamespaces.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(matchingTypes.Cast<INamespaceOrTypeSymbol>())
                                           .Distinct()
                                           .Where(NotNull)
                                           .Where(NotGlobalNamespace)
                                           .OrderBy(INamespaceOrTypeSymbolExtensions.CompareNamespaceOrTypeSymbols)
                                           .Take(8)
                                           .ToList();

                            if (proposedImports.Count > 0)
                            {
                                cancellationToken.ThrowIfCancellationRequested();

                                foreach (var import in proposedImports)
                                {
                                    var action = new MyCodeAction(this.GetDescription(import, semanticModel, node), (c) =>
                                        this.AddImportAsync(node, import, document, placeSystemNamespaceFirst, cancellationToken));

                                    context.RegisterCodeFix(action, diagnostic);
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// General verifier for codefixes.
        /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes.
        /// Then gets the string after the codefix is applied and compares it with the expected result.
        /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true.
        /// </summary>
        /// <param name="language">The language the source code is in</param>
        /// <param name="analyzer">The analyzer to be applied to the source code</param>
        /// <param name="codeFixProvider">The codefix to be applied to the code wherever the relevant Diagnostic is found</param>
        /// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param>
        /// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
        /// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param>
        /// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
        private async Task VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int?codeFixIndex, bool allowNewCompilerDiagnostics)
        {
            var document            = CreateDocument(oldSource, language);
            var analyzerDiagnostics = await GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }, false);

            var compilerDiagnostics = await GetCompilerDiagnostics(document);

            var attempts = analyzerDiagnostics.Length;

            for (int i = 0; i < attempts; ++i)
            {
                var actions = new List <CodeAction>();
                var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
                await codeFixProvider.RegisterCodeFixesAsync(context);

                if (!actions.Any())
                {
                    break;
                }

                if (codeFixIndex != null)
                {
                    document = await ApplyFix(document, actions.ElementAt((int)codeFixIndex));

                    break;
                }

                document = await ApplyFix(document, actions.ElementAt(0));

                analyzerDiagnostics = await GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }, false);

                var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, await GetCompilerDiagnostics(document));

                // check if applying the code fix introduced any new compiler diagnostics
                if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
                {
                    // Format and get the compiler diagnostics again so that the locations make sense in the output
                    document = document.WithSyntaxRoot(Formatter.Format(await document.GetSyntaxRootAsync(), Formatter.Annotation, document.Project.Solution.Workspace));
                    newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, await GetCompilerDiagnostics(document));

                    var    diagnosticsString = string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString()));
                    var    newDocumentString = (await document.GetSyntaxRootAsync()).ToFullString();
                    string message           =
                        $"Fix introduced new compiler diagnostics:\r\n{diagnosticsString}\r\n\r\nNew document:\r\n{newDocumentString}\r\n";

                    message.Should().BeEmpty();
                }

                // check if there are analyzer diagnostics left after the code fix
                if (analyzerDiagnostics.Any())
                {
                    var    diagnosticsString = string.Join("\r\n", analyzerDiagnostics.Select(d => d.ToString()));
                    var    newDocumentString = (await document.GetSyntaxRootAsync()).ToFullString();
                    string message           =
                        $"Fix didn't fix compiler diagnostics:\r\n{diagnosticsString}\r\n\r\nNew document:\r\n{newDocumentString}\r\n";

                    message.Should().BeEmpty();
                }
            }

            // after applying all of the code fixes, compare the resulting string to the inputted one
            var actual = await GetStringFromDocument(document);

            actual.Should().Be(newSource);
        }
Esempio n. 13
0
        /// <summary>
        /// General verifier for codefixes.
        /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes.
        /// Then gets the string after the codefix is applied and compares it with the expected result.
        /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true.
        /// </summary>
        /// <param name="language">The language the source code is in</param>
        /// <param name="analyzers">The analyzers to be applied to the source code</param>
        /// <param name="codeFixProvider">The codefix to be applied to the code wherever the relevant Diagnostic is found</param>
        /// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param>
        /// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
        /// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param>
        /// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
        private void VerifyFix(string language, List <DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, string oldSource, string newSource, int?codeFixIndex, bool allowNewCompilerDiagnostics)
        {
            var document            = CreateDocument(oldSource, language, GetAdditionnalReferences());
            var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzers, new[] { document });
            var compilerDiagnostics = GetCompilerDiagnostics(document);

            foreach (Diagnostic diag in compilerDiagnostics)
            {
                Console.WriteLine("/!\\: " + diag.ToString());
            }
            //Some compiler diagnostic are simply warnings, we can not fail once a warning is present..
            //Assert.AreEqual(compilerDiagnostics.Count(),0);
            var attempts = analyzerDiagnostics.Length;

            for (int i = 0; i < attempts; ++i)
            {
                var actions = new List <CodeAction>();
                var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
                codeFixProvider.RegisterCodeFixesAsync(context).Wait();

                if (!actions.Any())
                {
                    break;
                }

                if (codeFixIndex != null)
                {
                    document = ApplyFix(document, actions.ElementAt((int)codeFixIndex));
                    break;
                }

                document            = ApplyFix(document, actions.ElementAt(0));
                analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzers, new[] { document });

                var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document));

                //check if applying the code fix introduced any new compiler diagnostics
                if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any())
                {
                    // Format and get the compiler diagnostics again so that the locations make sense in the output
                    document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace));
                    newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document));

                    Assert.IsTrue(false,
                                  string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n",
                                                string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())),
                                                document.GetSyntaxRootAsync().Result.ToFullString()));
                }

                //check if there are analyzer diagnostics left after the code fix
                if (!analyzerDiagnostics.Any())
                {
                    break;
                }
            }

            //after applying all of the code fixes, compare the resulting string to the inputted one
            var actual = GetStringFromDocument(document);

            Assert.AreEqual(newSource, actual);
        }
Esempio n. 14
0
        private static async Task <Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray <DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int?codeFixIndex, Document document, int maxNumberOfIterations, CancellationToken cancellationToken)
        {
            var previousDiagnostics = ImmutableArray.Create <Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return(null);
            }

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--maxNumberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                string equivalenceKey = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    var actions = new List <CodeAction>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, codeFixProvider.FixableDiagnosticIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);

                if (action == null)
                {
                    return(document);
                }

                var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false);

                if (fixedDocument != document)
                {
                    done = false;
                    var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                    document = document.WithText(newText);
                }
            }while (!done);

            return(document);
        }
 public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
 {
     // Fixer not yet implemented.
     return(Task.CompletedTask);
 }
 public override Task RegisterCodeFixesAsync(CodeFixContext context)
 {
     RegisterCodeFix(context, CSharpAnalyzersResources.Simplify_default_expression, nameof(CSharpAnalyzersResources.Simplify_default_expression));
     return(Task.CompletedTask);
 }
Esempio n. 17
0
 public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) => BaseRegisterCodeFixesAsync(context);
        private static Func <CancellationToken, Task <Document> > GetCreateChangedDocument(CodeFixContext context, SyntaxNode node)
        {
            switch (node.Kind())
            {
            case SyntaxKind.MethodDeclaration:
            {
                var methodDeclaration = (MethodDeclarationSyntax)node;

                SyntaxToken semicolonToken = methodDeclaration.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                ParameterListSyntax parameterList = methodDeclaration.ParameterList;

                if (parameterList == null)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        MethodDeclarationSyntax newNode = methodDeclaration
                                                          .WithParameterList(parameterList.AppendToTrailingTrivia(semicolonToken.GetAllTrivia()))
                                                          .WithSemicolonToken(default(SyntaxToken))
                                                          .WithBody(Block())
                                                          .WithFormatterAnnotation();

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }

            case SyntaxKind.ConstructorDeclaration:
            {
                var constructorDeclaration = (ConstructorDeclarationSyntax)node;

                SyntaxToken semicolonToken = constructorDeclaration.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                ParameterListSyntax parameterList = constructorDeclaration.ParameterList;

                if (parameterList == null)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        ConstructorDeclarationSyntax newNode = constructorDeclaration
                                                               .WithParameterList(parameterList.AppendToTrailingTrivia(semicolonToken.GetAllTrivia()))
                                                               .WithSemicolonToken(default(SyntaxToken))
                                                               .WithBody(Block())
                                                               .WithFormatterAnnotation();

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }

            case SyntaxKind.DestructorDeclaration:
            {
                var destructorDeclaration = (DestructorDeclarationSyntax)node;

                SyntaxToken semicolonToken = destructorDeclaration.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                ParameterListSyntax parameterList = destructorDeclaration.ParameterList;

                if (parameterList == null)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        DestructorDeclarationSyntax newNode = destructorDeclaration
                                                              .WithParameterList(parameterList.AppendToTrailingTrivia(semicolonToken.GetAllTrivia()))
                                                              .WithSemicolonToken(default(SyntaxToken))
                                                              .WithBody(Block())
                                                              .WithFormatterAnnotation();

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }

            case SyntaxKind.OperatorDeclaration:
            {
                var operatorDeclaration = (OperatorDeclarationSyntax)node;

                SyntaxToken semicolonToken = operatorDeclaration.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                ParameterListSyntax parameterList = operatorDeclaration.ParameterList;

                if (parameterList == null)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        OperatorDeclarationSyntax newNode = operatorDeclaration
                                                            .WithParameterList(parameterList.AppendToTrailingTrivia(semicolonToken.GetAllTrivia()))
                                                            .WithSemicolonToken(default(SyntaxToken))
                                                            .WithBody(Block())
                                                            .WithFormatterAnnotation();

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }

            case SyntaxKind.ConversionOperatorDeclaration:
            {
                var conversionOperatorDeclaration = (ConversionOperatorDeclarationSyntax)node;

                SyntaxToken semicolonToken = conversionOperatorDeclaration.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                ParameterListSyntax parameterList = conversionOperatorDeclaration.ParameterList;

                if (parameterList == null)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        ConversionOperatorDeclarationSyntax newNode = conversionOperatorDeclaration
                                                                      .WithParameterList(parameterList.AppendToTrailingTrivia(semicolonToken.GetAllTrivia()))
                                                                      .WithSemicolonToken(default(SyntaxToken))
                                                                      .WithBody(Block())
                                                                      .WithFormatterAnnotation();

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }

            case SyntaxKind.GetAccessorDeclaration:
            case SyntaxKind.SetAccessorDeclaration:
            {
                var accessorDeclaration = (AccessorDeclarationSyntax)node;

                SyntaxToken semicolonToken = accessorDeclaration.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        AccessorDeclarationSyntax newNode = accessorDeclaration
                                                            .WithSemicolonToken(default(SyntaxToken))
                                                            .WithBody(Block(
                                                                          Token(default(SyntaxTriviaList), SyntaxKind.OpenBraceToken, TriviaList(ElasticSpace)),
                                                                          default(SyntaxList <StatementSyntax>),
                                                                          Token(default(SyntaxTriviaList), SyntaxKind.CloseBraceToken, semicolonToken.LeadingAndTrailingTrivia())));

                        SyntaxToken keyword = newNode.Keyword;

                        if (!keyword.HasTrailingTrivia)
                        {
                            newNode = newNode.WithKeyword(keyword.WithTrailingTrivia(ElasticSpace));
                        }

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }

            case SyntaxKind.LocalFunctionStatement:
            {
                var localFunction = (LocalFunctionStatementSyntax)node;

                SyntaxToken semicolonToken = localFunction.SemicolonToken;

                if (semicolonToken.Kind() == SyntaxKind.None)
                {
                    break;
                }

                ParameterListSyntax parameterList = localFunction.ParameterList;

                if (parameterList == null)
                {
                    break;
                }

                return(cancellationToken =>
                    {
                        LocalFunctionStatementSyntax newNode = localFunction
                                                               .WithParameterList(parameterList.AppendToTrailingTrivia(semicolonToken.GetAllTrivia()))
                                                               .WithSemicolonToken(default(SyntaxToken))
                                                               .WithBody(Block())
                                                               .WithFormatterAnnotation();

                        return context.Document.ReplaceNodeAsync(node, newNode, cancellationToken);
                    });
            }
            }

            Debug.Fail(node.Kind().ToString());

            return(null);
        }
Esempio n. 19
0
 protected abstract Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context);
Esempio n. 20
0
        private async Task CreateSpellCheckCodeIssueAsync(CodeFixContext context, TSimpleName nameNode, string nameText, CancellationToken cancellationToken)
        {
            var document = context.Document;
            var service  = CompletionService.GetService(document);

            // Disable snippets from ever appearing in the completion items. It's
            // very unlikely the user would ever mispell a snippet, then use spell-
            // checking to fix it, then try to invoke the snippet.
            var originalOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var options = originalOptions.WithChangedOption(CompletionOptions.SnippetsBehavior, document.Project.Language, SnippetsRule.NeverInclude);

            var completionList = await service.GetCompletionsAsync(
                document, nameNode.SpanStart, options : options, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (completionList == null)
            {
                return;
            }

            var onlyConsiderGenerics = IsGeneric(nameNode);
            var results = new MultiDictionary <double, string>();

            using (var similarityChecker = new WordSimilarityChecker(nameText, substringsAreSimilar: true))
            {
                foreach (var item in completionList.Items)
                {
                    if (onlyConsiderGenerics && !IsGeneric(item))
                    {
                        continue;
                    }

                    var candidateText = item.FilterText;
                    if (!similarityChecker.AreSimilar(candidateText, out var matchCost))
                    {
                        continue;
                    }

                    var insertionText = await GetInsertionTextAsync(document, item, cancellationToken : cancellationToken).ConfigureAwait(false);

                    results.Add(matchCost, insertionText);
                }
            }

            var codeActions = results.OrderBy(kvp => kvp.Key)
                              .SelectMany(kvp => kvp.Value.Order())
                              .Where(t => t != nameText)
                              .Take(3)
                              .Select(n => CreateCodeAction(nameNode, nameText, n, document))
                              .ToImmutableArrayOrEmpty <CodeAction>();

            if (codeActions.Length > 1)
            {
                // Wrap the spell checking actions into a single top level suggestion
                // so as to not clutter the list.
                context.RegisterCodeFix(new MyCodeAction(
                                            String.Format(FeaturesResources.Spell_check_0, nameText), codeActions), context.Diagnostics);
            }
            else
            {
                context.RegisterFixes(codeActions, context.Diagnostics);
            }
        }
        private static async Task <Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray <DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int?codeFixIndex, Document document, int numberOfIterations, CancellationToken cancellationToken)
        {
            int expectedNumberOfIterations = numberOfIterations;

            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create <Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return(null);
            }

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--numberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                string equivalenceKey = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                    {
                        // do not pass unsupported diagnostics to a code fix provider
                        continue;
                    }

                    var actions = new List <CodeAction>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                IEnumerable <string> analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
                IEnumerable <string> compilerDiagnosticIds = codeFixProvider.FixableDiagnosticIds.Where(x => x.StartsWith("CS", StringComparison.Ordinal));
                IEnumerable <string> disabledDiagnosticIds = document.Project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
                IEnumerable <string> relevantIds           = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
                FixAllContext        fixAllContext         = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);

                if (action == null)
                {
                    return(document);
                }

                var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false);

                if (fixedDocument != document)
                {
                    done = false;
                    var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                    document = document.WithText(newText);
                }
            }while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                Assert.Equal($"{expectedNumberOfIterations} iterations", $"{expectedNumberOfIterations - numberOfIterations} iterations");
            }

            return(document);
        }
        private static async Task <Document> GetSingleAnalyzerDocumentAsync(ImmutableArray <DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int?codeFixIndex, Document document, int numberOfIterations, CancellationToken cancellationToken)
        {
            int expectedNumberOfIterations = numberOfIterations;

            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create <Diagnostic>();

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--numberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of code fix iterations was exceeded");
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;
                for (var i = 0; i < analyzerDiagnostics.Length; i++)
                {
                    if (!codeFixProvider.FixableDiagnosticIds.Contains(analyzerDiagnostics[i].Id))
                    {
                        // do not pass unsupported diagnostics to a code fix provider
                        continue;
                    }

                    var actions = new List <CodeAction>();
                    var context = new CodeFixContext(document, analyzerDiagnostics[i], (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                    if (actions.Count > 0)
                    {
                        var fixedDocument = await ApplyFixAsync(document, actions.ElementAt(codeFixIndex.GetValueOrDefault(0)), cancellationToken).ConfigureAwait(false);

                        if (fixedDocument != document)
                        {
                            done = false;
                            var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                            // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                            document = document.WithText(newText);
                            break;
                        }
                    }
                }
            }while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                Assert.Equal($"{expectedNumberOfIterations} iterations", $"{expectedNumberOfIterations - numberOfIterations} iterations");
            }

            return(document);
        }
Esempio n. 23
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document          = context.Document;
            var span              = context.Span;
            var diagnostics       = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project    = document.Project;
            var diagnostic = diagnostics.First();
            var root       = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var node = root.FindToken(span.Start).GetAncestors <SyntaxNode>().First(n => n.Span.Contains(span));

            using (Logger.LogBlock(FunctionId.Refactoring_FullyQualify, cancellationToken))
            {
                // Has to be a simple identifier or generic name.
                if (node != null && CanFullyQualify(diagnostic, ref node))
                {
                    var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    var matchingTypes = await this.GetMatchingTypesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                    var matchingNamespaces = await this.GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                    if (matchingTypes != null || matchingNamespaces != null)
                    {
                        matchingTypes      = matchingTypes ?? SpecializedCollections.EmptyEnumerable <SymbolResult>();
                        matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyEnumerable <SymbolResult>();

                        var matchingTypeContainers      = FilterAndSort(GetContainers(matchingTypes, semanticModel.Compilation));
                        var matchingNamespaceContainers = FilterAndSort(GetContainers(matchingNamespaces, semanticModel.Compilation));

                        var proposedContainers =
                            matchingTypeContainers.Concat(matchingNamespaceContainers)
                            .Distinct()
                            .Take(MaxResults);

                        var displayService = project.LanguageServices.GetService <ISymbolDisplayService>();

                        foreach (var container in proposedContainers)
                        {
                            var containerName = displayService.ToMinimalDisplayString(semanticModel, node.SpanStart, container);

                            var    syntaxFacts = document.Project.LanguageServices.GetService <ISyntaxFactsService>();
                            string name;
                            int    arity;
                            syntaxFacts.GetNameAndArityOfSimpleName(node, out name, out arity);

                            // Actual member name might differ by case.
                            string memberName;
                            if (this.IgnoreCase)
                            {
                                var member = container.GetMembers(name).FirstOrDefault();
                                memberName = member != null ? member.Name : name;
                            }
                            else
                            {
                                memberName = name;
                            }

                            var codeAction = new MyCodeAction(
                                $"{containerName}.{memberName}",
                                c => ProcessNode(document, node, containerName, c));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }
                }
            }
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            foreach (var diagnostic in context.Diagnostics)
            {
                var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken);

                var compilation = await context.Document.Project.GetCompilationAsync(context.CancellationToken);

                if (compilation is null)
                {
                    continue;
                }

                INamedTypeSymbol?bclAsyncDisposableType = compilation.GetTypeByMetadataName(Types.BclAsyncDisposable.FullName);
                if (bclAsyncDisposableType is null)
                {
                    continue;
                }

                var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken);

                var generator = SyntaxGenerator.GetGenerator(context.Document);
                var originalTypeDeclaration = generator.TryGetContainingDeclaration(syntaxRoot.FindNode(diagnostic.Location.SourceSpan));
                if (originalTypeDeclaration is null)
                {
                    continue;
                }

                context.RegisterCodeFix(
                    CodeAction.Create(
                        Strings.VSTHRD112_CodeFix_Title,
                        ct =>
                {
                    // Declare that the type implements the System.IAsyncDisposable interface.
                    var newBaseType     = generator.TypeExpression(bclAsyncDisposableType);
                    var typeDeclaration = generator.AddInterfaceType(originalTypeDeclaration, newBaseType);

                    // Implement the interface, if we're on a non-interface type.
                    if (semanticModel.GetDeclaredSymbol(originalTypeDeclaration, ct) is ITypeSymbol changedSymbol && changedSymbol.TypeKind != TypeKind.Interface)
                    {
                        var disposeAsyncMethod = (IMethodSymbol)bclAsyncDisposableType.GetMembers().Single();
                        typeDeclaration        = generator.AddMembers(
                            typeDeclaration,
                            generator.AsPrivateInterfaceImplementation(
                                generator.MethodDeclaration(
                                    disposeAsyncMethod.Name,
                                    returnType: generator.TypeExpression(disposeAsyncMethod.ReturnType),
                                    accessibility: Accessibility.Public,
                                    statements: new SyntaxNode[]
                        {
                            generator.ReturnStatement(
                                generator.ObjectCreationExpression(
                                    disposeAsyncMethod.ReturnType,
                                    generator.InvocationExpression(
                                        generator.MemberAccessExpression(generator.ThisExpression(), "DisposeAsync")))),
                        }),
                                generator.TypeExpression(bclAsyncDisposableType)));
                    }

                    return(Task.FromResult(context.Document.WithSyntaxRoot(syntaxRoot.ReplaceNode(originalTypeDeclaration, typeDeclaration))));
                },
 protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax)
 {
     AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax);
 }
Esempio n. 26
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            SyntaxNode node = token.Parent;

            if (!CSharpFacts.CanHaveModifiers(node.Kind()))
            {
                node = node.FirstAncestor(f => CSharpFacts.CanHaveModifiers(f.Kind()));
            }

            Debug.Assert(node != null, $"{nameof(node)} is null");

            if (node == null)
            {
                return;
            }

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

                    SyntaxTokenList modifiers = SyntaxInfo.ModifierListInfo(node).Modifiers;

                    if (modifiers.Contains(token))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token);
                        break;
                    }
                    else if (IsInterfaceMemberOrExplicitInterfaceImplementation(node))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, modifiers, f =>
                            {
                                switch (f.Kind())
                                {
                                case SyntaxKind.PublicKeyword:
                                case SyntaxKind.ProtectedKeyword:
                                case SyntaxKind.InternalKeyword:
                                case SyntaxKind.PrivateKeyword:
                                case SyntaxKind.StaticKeyword:
                                case SyntaxKind.VirtualKeyword:
                                case SyntaxKind.OverrideKeyword:
                                case SyntaxKind.AbstractKeyword:
                                    {
                                        return(true);
                                    }
                                }

                                return(false);
                            });
                    }
                    else if (node.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration, SyntaxKind.EventFieldDeclaration) &&
                             node.IsParentKind(SyntaxKind.StructDeclaration) &&
                             modifiers.Contains(SyntaxKind.VirtualKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword);
                    }
                    else if (node.IsKind(SyntaxKind.IndexerDeclaration) &&
                             modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword);
                    }
                    else if (node.IsKind(SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration, SyntaxKind.EventFieldDeclaration) &&
                             modifiers.Contains(SyntaxKind.AsyncKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MoreThanOneProtectionModifier:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AccessibilityModifiersMayNotBeUsedOnAccessorsInInterface:
                case CompilerDiagnosticIdentifiers.AccessModifiersAreNotAllowedOnStaticConstructors:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ModifiersCannotBePlacedOnEventAccessorDeclarations:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyMethodsClassesStructsOrInterfacesMayBePartial:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ClassCannotBeBothStaticAndSealed:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword, additionalKey: nameof(SyntaxKind.SealedKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.FieldCanNotBeBothVolatileAndReadOnly:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    var fieldDeclaration = (FieldDeclarationSyntax)node;

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.VolatileKeyword, additionalKey: nameof(SyntaxKind.VolatileKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, additionalKey: nameof(SyntaxKind.ReadOnlyKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.NewProtectedMemberDeclaredInSealedClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotContainProtectedMembers:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrPrivate);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.VirtualOrAbstractMembersCannotBePrivate:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveVirtualModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword));
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AbstractPropertiesCannotHavePrivateAccessors:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node, additionalKey: CodeFixIdentifiers.RemoveInvalidModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticMemberCannotBeMarkedOverrideVirtualOrAbstract:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    if (!node.IsParentKind(SyntaxKind.ClassDeclaration) ||
                        !((ClassDeclarationSyntax)node.Parent).Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword));
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword, additionalKey: nameof(SyntaxKind.OverrideKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword, additionalKey: nameof(SyntaxKind.AbstractKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncModifierCanOnlyBeUsedInMethodsThatHaveBody:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodCannotHaveAccessModifiersOrVirtualAbstractOverrideNewSealedOrExternModifiers:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, f =>
                        {
                            switch (f.Kind())
                            {
                            case SyntaxKind.PublicKeyword:
                            case SyntaxKind.ProtectedKeyword:
                            case SyntaxKind.InternalKeyword:
                            case SyntaxKind.PrivateKeyword:
                            case SyntaxKind.VirtualKeyword:
                            case SyntaxKind.AbstractKeyword:
                            case SyntaxKind.OverrideKeyword:
                            case SyntaxKind.NewKeyword:
                            case SyntaxKind.SealedKeyword:
                            case SyntaxKind.ExternKeyword:
                                {
                                    return(true);
                                }
                            }

                            return(false);
                        });

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeStatic:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveThisModifier))
                    {
                        var methodDeclaration = (MethodDeclarationSyntax)node;

                        ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0];

                        SyntaxToken modifier = parameter.Modifiers.Find(SyntaxKind.ThisKeyword);

                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, parameter, modifier, additionalKey: CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeDefinedInNonGenericStaticClass:
                {
                    if (!(node is ClassDeclarationSyntax classDeclaration))
                    {
                        return;
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier) &&
                        !classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveThisModifier))
                    {
                        IEnumerable <ParameterSyntax> thisParameters = classDeclaration.Members
                                                                       .Where(f => f.IsKind(SyntaxKind.MethodDeclaration))
                                                                       .Cast <MethodDeclarationSyntax>()
                                                                       .Select(f => f.ParameterList?.Parameters.FirstOrDefault())
                                                                       .Where(f => f?.Modifiers.Contains(SyntaxKind.ThisKeyword) == true);

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            thisParameters,
                            SyntaxKind.ThisKeyword,
                            title: "Remove 'this' modifier from extension methods",
                            additionalKey: CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoDefiningDeclarationFoundForImplementingDeclarationOfPartialMethod:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodHasParameterModifierThisWhichIsNotOnFirstParameter:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveThisModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, token.Parent, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotDeclareInstanceMembersInStaticClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotHaveInstanceConstructors:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassNonStatic))
                    {
                        var classDeclaration = (ClassDeclarationSyntax)node.Parent;

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            classDeclaration,
                            classDeclaration.Modifiers.Find(SyntaxKind.StaticKeyword),
                            title: "Make containing class non-static",
                            additionalKey: CodeFixIdentifiers.MakeContainingClassNonStatic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ElementsDefinedInNamespaceCannotBeExplicitlyDeclaredAsPrivateProtectedOrProtectedInternal:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternal);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NamespaceAlreadyContainsDefinition:
                case CompilerDiagnosticIdentifiers.TypeAlreadyContainsDefinition:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    if (!node.IsKind(
                            SyntaxKind.ClassDeclaration,
                            SyntaxKind.StructDeclaration,
                            SyntaxKind.InterfaceDeclaration,
                            SyntaxKind.MethodDeclaration))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ISymbol symbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken);

                    ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences;

                    if (syntaxReferences.Length <= 1)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax(context.CancellationToken)),
                        SyntaxKind.PartialKeyword);

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoSuitableMethodFoundToOverride:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncMethodsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.IteratorsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBePassedAsRefOrOutValue:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveRefModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.RefKeyword, additionalKey: nameof(SyntaxKind.RefKeyword));
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveOutModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OutKeyword, additionalKey: nameof(SyntaxKind.OutKeyword));
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotHaveInstancePropertyOrFieldInitializersInStruct:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberMustDeclareBodyBecauseItIsNotMarkedAbstractExternOrPartial:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddModifierAbstract) &&
                        node.Kind() == SyntaxKind.MethodDeclaration &&
                        (node.Parent as ClassDeclarationSyntax)?.Modifiers.Contains(SyntaxKind.AbstractKeyword) == true)
                    {
                        ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NewVirtualMemberInSealedClass:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveVirtualModifier))
                    {
                        if (node is AccessorDeclarationSyntax &&
                            SyntaxInfo.ModifierListInfo(node.Parent.Parent).IsVirtual)
                        {
                            node = node.Parent.Parent;
                        }

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            node,
                            SyntaxKind.VirtualKeyword,
                            additionalKey: CodeFixIdentifiers.RemoveVirtualModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassUnsealed) &&
                        node.Parent is ClassDeclarationSyntax classDeclaration)
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            classDeclaration,
                            SyntaxKind.SealedKeyword,
                            title: "Make containing class unsealed",
                            additionalKey: CodeFixIdentifiers.MakeContainingClassUnsealed);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.InstanceFieldsOfReadOnlyStructsMustBeReadOnly:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeMemberReadOnly))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.ReadOnlyKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberCannotBeSealedBecauseItIsNotOverride:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveSealedModifier))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (semanticModel.GetDiagnostic(
                            CompilerDiagnosticIdentifiers.MemberHidesInheritedMemberToMakeCurrentMethodOverrideThatImplementationAddOverrideKeyword,
                            CSharpUtility.GetIdentifier(node).Span,
                            context.CancellationToken) != null)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword);
                    break;
                }
                }
            }
        }
Esempio n. 27
0
 public override Task RegisterCodeFixesAsync(CodeFixContext context)
 {
     RegisterCodeFix(context, AnalyzersResources.Collection_initialization_can_be_simplified, nameof(AnalyzersResources.Collection_initialization_can_be_simplified));
     return(Task.CompletedTask);
 }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.UseYieldReturnInsteadOfReturn,
                    CodeFixIdentifiers.RemoveReturnKeyword,
                    CodeFixIdentifiers.RemoveReturnExpression))
            {
                return;
            }

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

            ReturnStatementSyntax returnStatement = root
                                                    .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                    .FirstAncestorOrSelf <ReturnStatementSyntax>();

            Debug.Assert(returnStatement != null, $"{nameof(returnStatement)} is null");

            if (returnStatement == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotReturnValueFromIterator:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn))
                    {
                        break;
                    }

                    ExpressionSyntax expression = returnStatement.Expression;

                    if (expression != null)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.IsKind(SymbolKind.Method) == true)
                        {
                            var methodSymbol = (IMethodSymbol)containingSymbol;

                            ITypeSymbol returnType = methodSymbol.ReturnType;

                            var replacementKind = SyntaxKind.None;

                            if (returnType.SpecialType == SpecialType.System_Collections_IEnumerable)
                            {
                                if (semanticModel
                                    .GetTypeSymbol(expression, context.CancellationToken)
                                    .IsIEnumerableOrConstructedFromIEnumerableOfT())
                                {
                                    replacementKind = SyntaxKind.ForEachStatement;
                                }
                                else
                                {
                                    replacementKind = SyntaxKind.YieldReturnStatement;
                                }
                            }
                            else if (returnType.IsNamedType())
                            {
                                var namedTypeSymbol = (INamedTypeSymbol)returnType;

                                if (namedTypeSymbol.IsConstructedFromIEnumerableOfT())
                                {
                                    if (semanticModel.IsImplicitConversion(expression, namedTypeSymbol.TypeArguments[0]))
                                    {
                                        replacementKind = SyntaxKind.YieldReturnStatement;
                                    }
                                    else
                                    {
                                        replacementKind = SyntaxKind.ForEachStatement;
                                    }
                                }
                            }

                            if (replacementKind == SyntaxKind.YieldReturnStatement ||
                                (replacementKind == SyntaxKind.ForEachStatement && !returnStatement.SpanContainsDirectives()))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Use yield return instead of return",
                                    cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, replacementKind, semanticModel, cancellationToken),
                                    GetEquivalenceKey(diagnostic));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.SinceMethodReturnsVoidReturnKeywordMustNotBeFollowedByObjectExpression:
                case CompilerDiagnosticIdentifiers.SinceMethodIsAsyncMethodThatReturnsTaskReturnKeywordMustNotBeFollowedByObjectExpression:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveReturnExpression))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol symbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (symbol?.IsMethod() == true)
                        {
                            var methodSymbol = (IMethodSymbol)symbol;

                            if (methodSymbol.ReturnsVoid ||
                                methodSymbol.ReturnType.Equals(semanticModel.GetTypeByMetadataName(MetadataNames.System_Threading_Tasks_Task)))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Remove return expression",
                                    cancellationToken =>
                                    {
                                        ReturnStatementSyntax newNode = returnStatement
                                                                        .WithExpression(null)
                                                                        .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnExpression));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveReturnKeyword))
                    {
                        ExpressionSyntax expression = returnStatement.Expression;

                        if (expression.IsKind(
                                SyntaxKind.InvocationExpression,
                                SyntaxKind.ObjectCreationExpression,
                                SyntaxKind.PreDecrementExpression,
                                SyntaxKind.PreIncrementExpression,
                                SyntaxKind.PostDecrementExpression,
                                SyntaxKind.PostIncrementExpression) ||
                            expression is AssignmentExpressionSyntax)
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove 'return'",
                                cancellationToken =>
                                {
                                    SyntaxTriviaList leadingTrivia = returnStatement
                                                                     .GetLeadingTrivia()
                                                                     .AddRange(returnStatement.ReturnKeyword.TrailingTrivia.EmptyIfWhitespace())
                                                                     .AddRange(expression.GetLeadingTrivia().EmptyIfWhitespace());

                                    ExpressionStatementSyntax newNode = SyntaxFactory.ExpressionStatement(
                                        expression.WithLeadingTrivia(leadingTrivia),
                                        returnStatement.SemicolonToken);

                                    return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                                },
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnKeyword));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }
                }
            }
        }
 public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
 {
     // This is to get rid of warning CS1998, please remove when implementing this analyzer
     await new Task(() => { }).ConfigureAwait(false);
     throw new NotImplementedException();
 }
Esempio n. 30
0
        private async Task <Project> FixEachAnalyzerDiagnosticAsync(ImmutableArray <DiagnosticAnalyzer> analyzers, ImmutableArray <CodeFixProvider> codeFixProviders, int?codeFixIndex, string?codeFixEquivalenceKey, Project project, int numberOfIterations, IVerifier verifier, CancellationToken cancellationToken)
        {
            var expectedNumberOfIterations = numberOfIterations;

            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create <Diagnostic>();

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, CompilerDiagnostics, cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                verifier.True(--numberOfIterations >= -1, "The upper limit for the number of code fix iterations was exceeded");

                previousDiagnostics = analyzerDiagnostics;

                done = true;
                var anyActions = false;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    var actions = new List <CodeAction>();

                    foreach (var codeFixProvider in codeFixProviders)
                    {
                        if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                        {
                            // do not pass unsupported diagnostics to a code fix provider
                            continue;
                        }

                        var context = new CodeFixContext(project.GetDocument(diagnostic.Location.SourceTree), diagnostic, (a, d) => actions.Add(a), cancellationToken);
                        await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    }

                    var actionToApply = TryGetCodeActionToApply(actions, codeFixIndex, codeFixEquivalenceKey, verifier);
                    if (actionToApply != null)
                    {
                        anyActions = true;

                        var fixedProject = await ApplyFixAsync(project, actionToApply, cancellationToken).ConfigureAwait(false);

                        if (fixedProject != project)
                        {
                            done = false;

                            project = await RecreateProjectDocumentsAsync(fixedProject, verifier, cancellationToken).ConfigureAwait(false);

                            break;
                        }
                    }
                }

                if (!anyActions)
                {
                    verifier.True(done, "Expected to be done executing actions.");

                    // Avoid counting iterations that do not provide any code actions
                    numberOfIterations++;
                }
            }while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                verifier.Equal(expectedNumberOfIterations, expectedNumberOfIterations - numberOfIterations, $"Expected '{expectedNumberOfIterations}' iterations but found '{expectedNumberOfIterations - numberOfIterations}' iterations.");
            }
            else
            {
                verifier.True(numberOfIterations >= 0, "The upper limit for the number of code fix iterations was exceeded");
            }

            return(project);
        }
        /// <inheritdoc/>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document   = context.Document;
            var syntaxRoot = await document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            var semanticModel = await document.GetSemanticModelAsync(context.CancellationToken)
                                .ConfigureAwait(false);

            foreach (var diagnostic in context.Diagnostics)
            {
                var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start);
                if (string.IsNullOrEmpty(token.ValueText))
                {
                    continue;
                }

                if (diagnostic.Id == WPF0004ClrMethodShouldMatchRegisteredName.DiagnosticId)
                {
                    var methodDeclaration = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                                            .FirstAncestorOrSelf <MethodDeclarationSyntax>();

                    if (methodDeclaration == null || methodDeclaration.IsMissing)
                    {
                        continue;
                    }

                    var method = semanticModel.GetDeclaredSymbol(methodDeclaration) as IMethodSymbol;

                    if (method == null)
                    {
                        continue;
                    }

                    IFieldSymbol backingField;
                    if (ClrMethod.IsAttachedSetMethod(
                            method,
                            semanticModel,
                            context.CancellationToken,
                            out backingField))
                    {
                        TryUpdateName(
                            context,
                            backingField,
                            semanticModel,
                            syntaxRoot,
                            token,
                            "Set",
                            diagnostic);

                        continue;
                    }

                    if (ClrMethod.IsAttachedGetMethod(
                            method,
                            semanticModel,
                            context.CancellationToken,
                            out backingField))
                    {
                        TryUpdateName(
                            context,
                            backingField,
                            semanticModel,
                            syntaxRoot,
                            token,
                            "Get",
                            diagnostic);
                    }
                }
                else if (diagnostic.Id == WPF0005PropertyChangedCallbackShouldMatchRegisteredName.DiagnosticId)
                {
                    var node     = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                    var callback = node.FirstAncestorOrSelf <ArgumentSyntax>();
                    IdentifierNameSyntax nameExpression;
                    string registeredName;
                    if (WPF0005PropertyChangedCallbackShouldMatchRegisteredName.TryGetIdentifierAndRegisteredName(
                            callback,
                            semanticModel,
                            context.CancellationToken,
                            out nameExpression,
                            out registeredName))
                    {
                        var newName = $"On{registeredName}Changed";
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                $"Rename to: {newName}",
                                cancellationToken => RenameHelper.RenameSymbolAsync(context.Document, syntaxRoot, token, newName, cancellationToken),
                                nameof(RenameMethodCodeFixProvider)),
                            diagnostic);
                    }
                }
                else if (diagnostic.Id == WPF0006CoerceValueCallbackShouldMatchRegisteredName.DiagnosticId)
                {
                    var node     = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                    var callback = node.FirstAncestorOrSelf <ArgumentSyntax>();
                    IdentifierNameSyntax nameExpression;
                    string registeredName;
                    if (WPF0006CoerceValueCallbackShouldMatchRegisteredName.TryGetIdentifierAndRegisteredName(
                            callback,
                            semanticModel,
                            context.CancellationToken,
                            out nameExpression,
                            out registeredName))
                    {
                        var newName = $"Coerce{registeredName}";
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                $"Rename to: {newName}",
                                cancellationToken => RenameHelper.RenameSymbolAsync(context.Document, syntaxRoot, token, newName, cancellationToken),
                                nameof(RenameMethodCodeFixProvider)),
                            diagnostic);
                    }
                }
                else if (diagnostic.Id == WPF0007ValidateValueCallbackCallbackShouldMatchRegisteredName.DiagnosticId)
                {
                    var node     = syntaxRoot.FindNode(diagnostic.Location.SourceSpan);
                    var callback = node.FirstAncestorOrSelf <ArgumentSyntax>();
                    IdentifierNameSyntax nameExpression;
                    string registeredName;
                    if (WPF0007ValidateValueCallbackCallbackShouldMatchRegisteredName.TryGetIdentifierAndRegisteredName(
                            callback,
                            semanticModel,
                            context.CancellationToken,
                            out nameExpression,
                            out registeredName))
                    {
                        var newName = $"{registeredName}ValidateValue";
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                $"Rename to: {newName}",
                                cancellationToken => RenameHelper.RenameSymbolAsync(context.Document, syntaxRoot, token, newName, cancellationToken),
                                nameof(RenameMethodCodeFixProvider)),
                            diagnostic);
                    }
                }
            }
        }
Esempio n. 32
0
        private static async Task <Document> ApplyFixAsync(CancellationToken cancellationToken, CodeFixContext context, FieldDeclarationSyntax fieldDeclaration)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(cancellationToken)
                             .ConfigureAwait(false);

            var updatedModifiers = fieldDeclaration.Modifiers
                                   .WithStatic()
                                   .WithReadOnly();
            var updatedDeclaration = fieldDeclaration.WithModifiers(updatedModifiers);

            return(context.Document.WithSyntaxRoot(syntaxRoot.ReplaceNode(fieldDeclaration, updatedDeclaration)));
        }
        private IEnumerable<CodeAction> CreateActions(
            CodeFixContext context, Document document, Diagnostic diagnostic, 
            SyntaxNode node, SemanticModel semanticModel, 
            IEnumerable<INamespaceOrTypeSymbol> proposedContainers, 
            ISymbolDisplayService displayService)
        {
            foreach (var container in proposedContainers)
            {
                var containerName = displayService.ToMinimalDisplayString(semanticModel, node.SpanStart, container);

                var name = GetNodeName(document, node);

                // Actual member name might differ by case.
                string memberName;
                if (this.IgnoreCase)
                {
                    var member = container.GetMembers(name).FirstOrDefault();
                    memberName = member != null ? member.Name : name;
                }
                else
                {
                    memberName = name;
                }

                var codeAction = new MyCodeAction(
                    $"{containerName}.{memberName}",
                    c => ProcessNode(document, node, containerName, c));

                yield return codeAction;
            }
        }
Esempio n. 34
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out ConditionalExpressionSyntax conditionalExpression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.ParenthesizeConditionInConditionalExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Wrap condition in parentheses",
                        cancellationToken => ParenthesizeConditionInConditionalExpressionRefactoring.RefactorAsync(context.Document, conditionalExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseCoalesceExpressionInsteadOfConditionalExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use coalesce expression",
                        cancellationToken =>
                        {
                            return(SimplifyNullCheckRefactoring.RefactorAsync(
                                       context.Document,
                                       conditionalExpression,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.SimplifyConditionalExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify conditional expression",
                        cancellationToken =>
                        {
                            return(SimplifyConditionalExpressionRefactoring.RefactorAsync(
                                       context.Document,
                                       conditionalExpression,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.FormatConditionalExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Format ? and : on next line",
                        cancellationToken =>
                        {
                            return(FormatConditionalExpressionRefactoring.RefactorAsync(
                                       context.Document,
                                       conditionalExpression,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseConditionalAccessInsteadOfConditionalExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use conditional access",
                        cancellationToken =>
                        {
                            return(SimplifyNullCheckRefactoring.RefactorAsync(
                                       context.Document,
                                       conditionalExpression,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Document          doc = context.Document;
            CancellationToken cancellationToken = context.CancellationToken;
            SyntaxNode        root = await doc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            if (!(root.FindNode(context.Span) is SyntaxNode expression))
            {
                return;
            }

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

            var operation = semanticModel.GetOperation(expression, cancellationToken);

            // Not offering a code-fix for the variable declaration case
            if (!(operation is IBinaryOperation binaryOperation))
            {
                return;
            }

            IInvocationOperation invocationOperation;
            IOperation           otherOperation;

            if (binaryOperation.LeftOperand is IInvocationOperation invocationOperationOperand)
            {
                invocationOperation = invocationOperationOperand;
                otherOperation      = binaryOperation.RightOperand;
            }
            else
            {
                invocationOperation = (IInvocationOperation)binaryOperation.RightOperand;
                otherOperation      = binaryOperation.LeftOperand;
            }

            switch (invocationOperation.Arguments.Length)
            {
            case 1:
            case 2:
                break;

            default:
                return;
            }

            var instanceOperation = invocationOperation.Instance;

            context.RegisterCodeFix(
                CodeAction.Create(
                    title: MicrosoftNetCoreAnalyzersResources.PreferStringContainsOverIndexOfTitle,
                    createChangedDocument: c => ReplaceBinaryOperationWithContains(doc, instanceOperation.Syntax, invocationOperation.Arguments, binaryOperation, c),
                    equivalenceKey: MicrosoftNetCoreAnalyzersResources.PreferStringContainsOverIndexOfTitle),
                context.Diagnostics);
            return;

            async Task <Document?> ReplaceBinaryOperationWithContains(Document document, SyntaxNode syntaxNode, ImmutableArray <IArgumentOperation> indexOfMethodArguments, IBinaryOperation binaryOperation, CancellationToken cancellationToken)
            {
                DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

                SyntaxGenerator generator          = editor.Generator;
                var             containsExpression = generator.MemberAccessExpression(syntaxNode, "Contains");
                SyntaxNode?     containsInvocation = null;
                int             numberOfArguments  = indexOfMethodArguments.Length;

                if (numberOfArguments == 1)
                {
                    var firstArgument = indexOfMethodArguments[0];
                    if (firstArgument.Parameter.Type.SpecialType == SpecialType.System_Char)
                    {
                        containsInvocation = generator.InvocationExpression(containsExpression, firstArgument.Syntax);
                    }
                    else
                    {
                        var systemNode = generator.IdentifierName("System");
                        var argument   = generator.MemberAccessExpression(generator.MemberAccessExpression(systemNode, "StringComparison"), "CurrentCulture");
                        containsInvocation = generator.InvocationExpression(containsExpression, firstArgument.Syntax, argument);
                    }
                }
                else
                {
                    int stringOrCharArgumentIndex, ordinalArgumentIndex;
                    if (indexOfMethodArguments[0].Value.Type.SpecialType == SpecialType.System_String || indexOfMethodArguments[0].Value.Type.SpecialType == SpecialType.System_Char)
                    {
                        stringOrCharArgumentIndex = 0;
                        ordinalArgumentIndex      = 1;
                    }
                    else
                    {
                        stringOrCharArgumentIndex = 1;
                        ordinalArgumentIndex      = 0;
                    }

                    var ordinalArgumentValue = indexOfMethodArguments[ordinalArgumentIndex].Value;
                    if (ordinalArgumentValue.ConstantValue.HasValue &&
                        ordinalArgumentValue.ConstantValue.Value is int intValue &&
                        (StringComparison)intValue == StringComparison.Ordinal)
                    {
                        containsInvocation = generator.InvocationExpression(containsExpression, indexOfMethodArguments[stringOrCharArgumentIndex].Syntax);
                    }
Esempio n. 36
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f => f.IsKind(
                        SyntaxKind.VariableDeclaration,
                        SyntaxKind.ForEachStatement,
                        SyntaxKind.Parameter,
                        SyntaxKind.DeclarationPattern,
                        SyntaxKind.DeclarationExpression,
                        SyntaxKind.LocalFunctionStatement)))
            {
                return;
            }

            if (node.IsKind(SyntaxKind.ForEachStatement, SyntaxKind.Parameter, SyntaxKind.DeclarationPattern, SyntaxKind.DeclarationExpression, SyntaxKind.LocalFunctionStatement))
            {
                return;
            }

            var variableDeclaration = (VariableDeclarationSyntax)node;

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ImplicitlyTypedVariablesCannotHaveMultipleDeclarators:
                case CompilerDiagnosticIdentifiers.ImplicitlyTypedVariablesCannotBeConstant:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseExplicitTypeInsteadOfVar))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeSyntax type = variableDeclaration.Type;

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, context.CancellationToken);

                    if (typeSymbol?.SupportsExplicitDeclaration() == true)
                    {
                        CodeAction codeAction = CodeActionFactory.ChangeType(context.Document, type, typeSymbol, semanticModel, equivalenceKey: GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.LocalVariableOrFunctionIsAlreadyDefinedInThisScope:
                case CompilerDiagnosticIdentifiers.LocalOrParameterCannotBeDeclaredInThisScopeBecauseThatNameIsUsedInEnclosingScopeToDefineLocalOrParameter:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceVariableDeclarationWithAssignment))
                    {
                        return;
                    }

                    if (!(variableDeclaration.Parent is LocalDeclarationStatementSyntax localDeclaration))
                    {
                        return;
                    }

                    VariableDeclaratorSyntax variableDeclarator = variableDeclaration.Variables.SingleOrDefault(shouldThrow: false);

                    if (variableDeclarator == null)
                    {
                        break;
                    }

                    ExpressionSyntax value = variableDeclarator.Initializer?.Value;

                    if (value == null)
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    VariableDeclaratorSyntax variableDeclarator2 = FindVariableDeclarator(
                        variableDeclarator.Identifier.ValueText,
                        semanticModel.GetEnclosingSymbolSyntax(localDeclaration.SpanStart, context.CancellationToken));

                    if (variableDeclarator2?.SpanStart < localDeclaration.SpanStart)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Replace variable declaration with assignment",
                            cancellationToken =>
                            {
                                ExpressionStatementSyntax newNode = CSharpFactory.SimpleAssignmentStatement(
                                    SyntaxFactory.IdentifierName(variableDeclarator.Identifier),
                                    value);

                                newNode = newNode
                                          .WithTriviaFrom(localDeclaration)
                                          .WithFormatterAnnotation();

                                return(context.Document.ReplaceNodeAsync(localDeclaration, newNode, cancellationToken));
                            },
                            GetEquivalenceKey(diagnostic));
                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var diagnostics = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project = document.Project;
            var diagnostic = diagnostics.First();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var node = root.FindToken(span.Start).GetAncestors<SyntaxNode>().First(n => n.Span.Contains(span));

            using (Logger.LogBlock(FunctionId.Refactoring_FullyQualify, cancellationToken))
            {
                // Has to be a simple identifier or generic name.
                if (node != null && CanFullyQualify(diagnostic, ref node))
                {
                    var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    var matchingTypes = await this.GetMatchingTypesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);
                    var matchingNamespaces = await this.GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                    if (matchingTypes != null || matchingNamespaces != null)
                    {
                        matchingTypes = matchingTypes ?? SpecializedCollections.EmptyEnumerable<ISymbol>();
                        matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyEnumerable<ISymbol>();

                        var matchingTypeContainers = FilterAndSort(GetContainers(matchingTypes, semanticModel.Compilation));
                        var matchingNamespaceContainers = FilterAndSort(GetContainers(matchingNamespaces, semanticModel.Compilation));

                        var proposedContainers =
                            matchingTypeContainers.Concat(matchingNamespaceContainers)
                                              .Distinct()
                                              .Take(MaxResults);

                        var displayService = project.LanguageServices.GetService<ISymbolDisplayService>();

                        foreach (var container in proposedContainers)
                        {
                            var containerName = displayService.ToMinimalDisplayString(semanticModel, node.SpanStart, container);

                            var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
                            string name;
                            int arity;
                            syntaxFacts.GetNameAndArityOfSimpleName(node, out name, out arity);

                            // Actual member name might differ by case.
                            string memberName;
                            if (this.IgnoreCase)
                            {
                                var member = container.GetMembers(name).FirstOrDefault();
                                memberName = member != null ? member.Name : name;
                            }
                            else
                            {
                                memberName = name;
                            }

                            var codeAction = new MyCodeAction(
                                $"{containerName}.{memberName}",
                                c => ProcessNode(document, node, containerName, c));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MarkOperatorAsPublicAndStatic))
            {
                return;
            }

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

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UserDefinedOperatorMustBeDeclaredStaticAndPublic:
                {
                    ModifierListInfo info = SyntaxInfo.ModifierListInfo(memberDeclaration);

                    string title = "Add ";

                    if (info.ExplicitAccessibility == Accessibility.Public)
                    {
                        title += "modifier 'static'";
                    }
                    else if (info.IsStatic)
                    {
                        title += "modifier 'public'";
                    }
                    else
                    {
                        title += "modifiers 'public static'";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        cancellationToken =>
                        {
                            SyntaxNode newNode = memberDeclaration;

                            if (info.Modifiers.ContainsAny(SyntaxKind.InternalKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.PrivateKeyword))
                            {
                                newNode = SyntaxAccessibility.WithoutExplicitAccessibility(newNode);
                            }

                            if (!info.Modifiers.Contains(SyntaxKind.PublicKeyword))
                            {
                                newNode = ModifierList.Insert(newNode, SyntaxKind.PublicKeyword);
                            }

                            if (!info.IsStatic)
                            {
                                newNode = ModifierList.Insert(newNode, SyntaxKind.StaticKeyword);
                            }

                            return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, cancellationToken));
                        },
                        base.GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Esempio n. 39
0
        private static async Task <Document> Fix(CodeFixContext context, SyntaxNode root, SyntaxGenerator generator, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            SyntaxNode node       = root.FindNode(context.Span);
            Diagnostic diagnostic = context.Diagnostics.First();

            switch (diagnostic.Properties[OperatorOverloadsHaveNamedAlternatesAnalyzer.DiagnosticKindText])
            {
            case OperatorOverloadsHaveNamedAlternatesAnalyzer.AddAlternateText:
                SyntaxNode       methodDeclaration      = generator.GetDeclaration(node, DeclarationKind.Operator) ?? generator.GetDeclaration(node, DeclarationKind.ConversionOperator);
                var              operatorOverloadSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken);
                INamedTypeSymbol typeSymbol             = operatorOverloadSymbol.ContainingType;

                // For C# the following `typeDeclarationSyntax` and `typeDeclaration` nodes are identical, but for VB they're different so in
                // an effort to keep this as language-agnostic as possible, the heavy-handed approach is used.
                SyntaxNode typeDeclarationSyntax = typeSymbol.DeclaringSyntaxReferences.First().GetSyntax(cancellationToken);
                SyntaxNode typeDeclaration       = generator.GetDeclaration(typeDeclarationSyntax,
                                                                            typeSymbol.TypeKind == TypeKind.Struct ? DeclarationKind.Struct : DeclarationKind.Class);

                SyntaxNode addedMember;
                IEnumerable <SyntaxNode> bodyStatements = generator.DefaultMethodBody(semanticModel.Compilation);
                if (OperatorOverloadsHaveNamedAlternatesAnalyzer.IsPropertyExpected(operatorOverloadSymbol.Name))
                {
                    // add a property
                    addedMember = generator.PropertyDeclaration(
                        name: OperatorOverloadsHaveNamedAlternatesAnalyzer.IsTrueText,
                        type: generator.TypeExpression(SpecialType.System_Boolean),
                        accessibility: Accessibility.Public,
                        modifiers: DeclarationModifiers.ReadOnly,
                        getAccessorStatements: bodyStatements);
                }
                else
                {
                    // add a method
                    ExpectedMethodSignature expectedSignature = GetExpectedMethodSignature(operatorOverloadSymbol, semanticModel.Compilation);

                    if (expectedSignature.Name == "CompareTo" && operatorOverloadSymbol.ContainingType.TypeKind == TypeKind.Class)
                    {
                        var nullCheck = generator.IfStatement(
                            generator.InvocationExpression(
                                generator.IdentifierName("ReferenceEquals"),
                                generator.IdentifierName(expectedSignature.Parameters.First().Item1),
                                generator.NullLiteralExpression()),
                            new[]
                        {
                            generator.ReturnStatement(generator.LiteralExpression(1))
                        });

                        bodyStatements = new[] { nullCheck }.Concat(bodyStatements);
                    }

                    addedMember = generator.MethodDeclaration(
                        name: expectedSignature.Name,
                        parameters: expectedSignature.Parameters.Select(p => generator.ParameterDeclaration(p.Item1, generator.TypeExpression(p.Item2))),
                        returnType: generator.TypeExpression(expectedSignature.ReturnType),
                        accessibility: Accessibility.Public,
                        modifiers: expectedSignature.IsStatic ? DeclarationModifiers.Static : DeclarationModifiers.None,
                        statements: bodyStatements);
                }

                SyntaxNode newTypeDeclaration = generator.AddMembers(typeDeclaration, addedMember);
                return(context.Document.WithSyntaxRoot(root.ReplaceNode(typeDeclaration, newTypeDeclaration)));

            case OperatorOverloadsHaveNamedAlternatesAnalyzer.FixVisibilityText:
                SyntaxNode   badVisibilityNode   = generator.GetDeclaration(node, DeclarationKind.Method) ?? generator.GetDeclaration(node, DeclarationKind.Property);
                ISymbol      badVisibilitySymbol = semanticModel.GetDeclaredSymbol(badVisibilityNode, cancellationToken);
                SymbolEditor symbolEditor        = SymbolEditor.Create(context.Document);
                ISymbol      newSymbol           = await symbolEditor.EditOneDeclarationAsync(badVisibilitySymbol,
                                                                                              (documentEditor, syntaxNode) => documentEditor.SetAccessibility(badVisibilityNode, Accessibility.Public), cancellationToken).ConfigureAwait(false);

                Document   newDocument = symbolEditor.GetChangedDocuments().Single();
                SyntaxNode newRoot     = await newDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                return(context.Document.WithSyntaxRoot(newRoot));

            default:
                return(context.Document);
            }
        }
Esempio n. 40
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindNode(root, context.Span, out SyntaxNode node))
            {
                return;
            }

            if (node is not SimpleNameSyntax simpleName)
            {
                return;
            }

            Document   document     = context.Document;
            Diagnostic diagnostic   = context.Diagnostics[0];
            string     diagnosticId = diagnostic.Id;

            if (diagnosticId == CompilerDiagnosticIdentifiers.CS0428_CannotConvertMethodGroupToNonDelegateType ||
                diagnosticId == CompilerDiagnosticIdentifiers.CS0119_NameIsNotValidInGivenContext)
            {
                if (!IsEnabled(diagnosticId, CodeFixIdentifiers.AddArgumentList, document, root.SyntaxTree))
                {
                    return;
                }

                if (!simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    return;
                }

                var memberAccess = (MemberAccessExpressionSyntax)simpleName.Parent;

                CodeAction codeAction = CodeAction.Create(
                    "Add argument list",
                    ct =>
                {
                    InvocationExpressionSyntax invocationExpression = InvocationExpression(
                        memberAccess.WithoutTrailingTrivia(),
                        ArgumentList().WithTrailingTrivia(memberAccess.GetTrailingTrivia()));

                    return(document.ReplaceNodeAsync(memberAccess, invocationExpression, ct));
                },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (diagnosticId == CompilerDiagnosticIdentifiers.CS0246_TypeOrNamespaceNameCouldNotBeFound)
            {
                if (IsEnabled(diagnosticId, CodeFixIdentifiers.ChangeArrayType, document, root.SyntaxTree) &&
                    (simpleName.Parent is ArrayTypeSyntax arrayType) &&
                    (arrayType.Parent is ArrayCreationExpressionSyntax arrayCreation) &&
                    object.ReferenceEquals(simpleName, arrayType.ElementType))
                {
                    ExpressionSyntax expression = arrayCreation.Initializer?.Expressions.FirstOrDefault();

                    if (expression != null)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.SupportsExplicitDeclaration() == true)
                        {
                            TypeSyntax newType = typeSymbol.ToTypeSyntax()
                                                 .WithSimplifierAnnotation()
                                                 .WithTriviaFrom(simpleName);

                            CodeAction codeAction = CodeAction.Create(
                                $"Change element type to '{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, simpleName.SpanStart, SymbolDisplayFormats.DisplayName)}'",
                                ct => document.ReplaceNodeAsync(simpleName, newType, ct),
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                            return;
                        }
                    }
                }

                if (IsEnabled(diagnosticId, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression, document, root.SyntaxTree))
                {
                    ExpressionSyntax expression = GetReturnExpression(simpleName);

                    if (expression != null)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }
                }
            }
        }
        public async Task CreatingAnImmutableArrayViaTheEmptyPropertyWithoutOpeningTheImmutableNamespace_CodeFixMakesTheCodeUseTheCreateMethod()
        {
            var code = @"
public static class Program
{
    public static void Main()
    {
        var array = System.Collections.Immutable.ImmutableArray<int>.Empty.Add(1);
    }
}";

            var expectedChangedCode = @"
public static class Program
{
    public static void Main()
    {
        var array = System.Collections.Immutable.ImmutableArray.Create(1);
    }
}";

            var(diagnostics, document, workspace) = await Utilities.GetDiagnosticsAdvanced(code);

            Assert.AreEqual(1, diagnostics.Length);

            var diagnostic = diagnostics[0];

            var codeFixProvider = new CreationCodeFixProvider();

            CodeAction registeredCodeAction = null;

            var context = new CodeFixContext(document, diagnostic, (codeAction, _) =>
            {
                if (registeredCodeAction != null)
                {
                    throw new Exception("Code action was registered more than once");
                }

                registeredCodeAction = codeAction;
            }, CancellationToken.None);

            await codeFixProvider.RegisterCodeFixesAsync(context);

            if (registeredCodeAction == null)
            {
                throw new Exception("Code action was not registered");
            }

            var operations = await registeredCodeAction.GetOperationsAsync(CancellationToken.None);

            foreach (var operation in operations)
            {
                operation.Apply(workspace, CancellationToken.None);
            }

            var updatedDocument = workspace.CurrentSolution.GetDocument(document.Id);


            var newCode = (await updatedDocument.GetTextAsync()).ToString();

            Assert.AreEqual(expectedChangedCode, newCode);
        }
Esempio n. 42
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.FormatDeclarationBraces:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Format braces",
                        cancellationToken => FormatDeclarationBracesRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {memberDeclaration.GetTitle()}",
                        cancellationToken => context.Document.RemoveMemberAsync(memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.AddDefaultAccessModifier:
                {
                    var accessibility = (Accessibility)Enum.Parse(
                        typeof(Accessibility),
                        context.Diagnostics[0].Properties[nameof(Accessibility)]);

                    CodeAction codeAction = CodeAction.Create(
                        "Add default access modifier",
                        cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.AddEmptyLineBetweenDeclarations:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Add empty line",
                        cancellationToken => AddEmptyLineBetweenDeclarationsRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantSealedModifier:
                {
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword);
                    break;
                }

                case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary semicolon",
                        cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ReorderModifiers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Reorder modifiers",
                        cancellationToken => ReorderModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.MarkFieldAsReadOnly:
                {
                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables;

                    string title = (declarators.Count == 1)
                                ? $"Mark '{declarators[0].Identifier.ValueText}' as read-only"
                                : "Mark fields as read-only";

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title);
                    break;
                }

                case DiagnosticIdentifiers.UseConstantInsteadOfField:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use constant instead of field",
                        cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseReadOnlyAutoProperty:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use read-only auto-property",
                        cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ReplaceCommentWithDocumentationComment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        ReplaceCommentWithDocumentationCommentRefactoring.Title,
                        cancellationToken => ReplaceCommentWithDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }