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; }
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); } } }
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); } }
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); }
/// <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); }
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); }
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); }
protected abstract Task RegisterCodeFixesAsync(SyntaxNode root, CodeFixContext context);
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); }
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); }
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; } } } }
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(); }
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); } } } }
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; } }
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); }
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; } } } }
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); } }
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); }
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; } } } }