protected override async Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor syntaxEditor, CodeActionOptionsProvider options, CancellationToken cancellationToken) { var nodesToRemove = new HashSet <SyntaxNode>(); // Create actions and keep their SpanStart. // Execute actions ordered descending by SpanStart to avoid conflicts. var actionsToPerform = new List <(int, Action)>(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var documentsToBeSearched = ImmutableHashSet.Create(document); foreach (var diagnostic in diagnostics) { var token = diagnostic.Location.FindToken(cancellationToken); var node = root.FindNode(diagnostic.Location.SourceSpan); if (IsCatchDeclarationIdentifier(token)) { (int, Action)pair = (token.Parent.SpanStart, () => syntaxEditor.ReplaceNode( token.Parent, token.Parent.ReplaceToken(token, default(SyntaxToken)).WithAdditionalAnnotations(Formatter.Annotation))); actionsToPerform.Add(pair); } else { nodesToRemove.Add(node); } var symbol = documentEditor.SemanticModel.GetDeclaredSymbol(node, cancellationToken); var referencedSymbols = await SymbolFinder.FindReferencesAsync(symbol, document.Project.Solution, documentsToBeSearched, cancellationToken).ConfigureAwait(false); foreach (var referencedSymbol in referencedSymbols) { if (referencedSymbol?.Locations != null) { foreach (var location in referencedSymbol.Locations) { var referencedSymbolNode = root.FindNode(location.Location.SourceSpan); if (referencedSymbolNode != null) { var nodeToRemoveOrReplace = GetNodeToRemoveOrReplace(referencedSymbolNode); if (nodeToRemoveOrReplace != null) { nodesToRemove.Add(nodeToRemoveOrReplace); } } } } } } MergeNodesToRemove(nodesToRemove); var blockFacts = document.GetLanguageService <IBlockFactsService>(); foreach (var node in nodesToRemove) { actionsToPerform.Add((node.SpanStart, () => RemoveOrReplaceNode(syntaxEditor, node, blockFacts))); } // Process nodes in reverse order // to complete with nested declarations before processing the outer ones. foreach (var node in actionsToPerform.OrderByDescending(n => n.Item1)) { node.Item2(); } }
public CSharpCodeFixOptionsProvider(AnalyzerConfigOptions options, CodeActionOptionsProvider fallbackOptions, HostLanguageServices languageServices) { _options = options; _fallbackOptions = fallbackOptions; _languageServices = languageServices; }
public static Task <ImmutableArray <CodeFixCollection> > GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptionsProvider fallbackOptions, bool isBlocking, CancellationToken cancellationToken) => service.StreamFixesAsync(document, range, fallbackOptions, isBlocking, cancellationToken).ToImmutableArrayAsync(cancellationToken);
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // Fix-All for this feature is somewhat complicated. As Object-Initializers // could be arbitrarily nested, we have to make sure that any edits we make // to one Object-Initializer are seen by any higher ones. In order to do this // we actually process each object-creation-node, one at a time, rewriting // the tree for each node. In order to do this effectively, we use the '.TrackNodes' // feature to keep track of all the object creation nodes as we make edits to // the tree. If we didn't do this, then we wouldn't be able to find the // second object-creation-node after we make the edit for the first one. var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var originalRoot = editor.OriginalRoot; var originalObjectCreationNodes = new Stack <TObjectCreationExpressionSyntax>(); foreach (var diagnostic in diagnostics) { var objectCreation = (TObjectCreationExpressionSyntax)originalRoot.FindNode( diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true); originalObjectCreationNodes.Push(objectCreation); } // We're going to be continually editing this tree. Track all the nodes we // care about so we can find them across each edit. document = document.WithSyntaxRoot(originalRoot.TrackNodes(originalObjectCreationNodes)); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); while (originalObjectCreationNodes.Count > 0) { var originalObjectCreation = originalObjectCreationNodes.Pop(); var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single(); var matches = UseNamedMemberInitializerAnalyzer <TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax> .Analyze( semanticModel, syntaxFacts, objectCreation, cancellationToken); if (matches == null || matches.Value.Length == 0) { continue; } var statement = objectCreation.FirstAncestorOrSelf <TStatementSyntax>(); Contract.ThrowIfNull(statement); var newStatement = GetNewStatement(statement, objectCreation, matches.Value) .WithAdditionalAnnotations(Formatter.Annotation); var subEditor = document.GetSyntaxEditor(currentRoot); subEditor.ReplaceNode(statement, newStatement); foreach (var match in matches) { subEditor.RemoveNode(match.Statement, SyntaxRemoveOptions.KeepUnbalancedDirectives); } document = document.WithSyntaxRoot(subEditor.GetChangedRoot()); semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); } editor.ReplaceNode(editor.OriginalRoot, currentRoot); }
public static ValueTask <ExtractMethodGenerationOptions> GetExtractMethodGenerationOptionsAsync(this Document document, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) => document.GetExtractMethodGenerationOptionsAsync(fallbackOptions.GetExtractMethodGenerationOptions(document.Project.LanguageServices), cancellationToken);
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider options, CancellationToken cancellationToken) { var methodDeclaration = (MethodDeclarationSyntax)diagnostics[0].AdditionalLocations[0].FindNode(cancellationToken); var newDocument = await ConvertToTopLevelStatementsAsync(document, methodDeclaration, cancellationToken).ConfigureAwait(false); var newRoot = await newDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); editor.ReplaceNode(editor.OriginalRoot, newRoot); }
protected abstract Task FixOneAsync( Document document, Diagnostic diagnostic, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken);
protected override Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider options, CancellationToken cancellationToken) { foreach (var diagnostic in diagnostics) { var node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var newDocCommentId = diagnostic.Properties[AbstractRemoveUnnecessaryAttributeSuppressionsDiagnosticAnalyzer.DocCommentIdKey]; editor.ReplaceNode(node, editor.Generator.LiteralExpression(newDocCommentId).WithTriviaFrom(node)); } return(Task.CompletedTask); }
public async Task <Document> CleanupAsync( Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // add one item for the code fixers we get from nuget, we'll do last var thirdPartyDiagnosticIdsAndTitles = ImmutableArray <(string diagnosticId, string?title)> .Empty; if (enabledDiagnostics.RunThirdPartyFixers) { thirdPartyDiagnosticIdsAndTitles = await GetThirdPartyDiagnosticIdsAndTitlesAsync(document, cancellationToken).ConfigureAwait(false); progressTracker.AddItems(thirdPartyDiagnosticIdsAndTitles.Length); } // add one item for the 'format' action if (enabledDiagnostics.FormatDocument) { progressTracker.AddItems(1); } // and one for 'remove/sort usings' if we're going to run that. var organizeUsings = enabledDiagnostics.OrganizeUsings.IsRemoveUnusedImportEnabled || enabledDiagnostics.OrganizeUsings.IsSortImportsEnabled; if (organizeUsings) { progressTracker.AddItems(1); } if (enabledDiagnostics.Diagnostics.Any()) { progressTracker.AddItems(enabledDiagnostics.Diagnostics.Length); } document = await ApplyCodeFixesAsync( document, enabledDiagnostics.Diagnostics, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); if (enabledDiagnostics.RunThirdPartyFixers) { document = await ApplyThirdPartyCodeFixesAsync( document, thirdPartyDiagnosticIdsAndTitles, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); } // do the remove usings after code fix, as code fix might remove some code which can results in unused usings. if (organizeUsings) { progressTracker.Description = this.OrganizeImportsDescription; document = await RemoveSortUsingsAsync( document, enabledDiagnostics.OrganizeUsings, fallbackOptions, cancellationToken).ConfigureAwait(false); progressTracker.ItemCompleted(); } if (enabledDiagnostics.FormatDocument) { var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); progressTracker.Description = FeaturesResources.Formatting_document; using (Logger.LogBlock(FunctionId.CodeCleanup_Format, cancellationToken)) { document = await Formatter.FormatAsync(document, formattingOptions, cancellationToken).ConfigureAwait(false); progressTracker.ItemCompleted(); } } if (enabledDiagnostics.RunThirdPartyFixers) { document = await ApplyThirdPartyCodeFixesAsync( document, thirdPartyDiagnosticIdsAndTitles, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); } return(document); }
protected override Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) => WrapFixAsync( document, diagnostics, (d, localFunction, captures) => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync( d, localFunction, captures, editor, fallbackOptions, cancellationToken), cancellationToken);
private async Task ApplySuppressionFixAsync(IEnumerable <DiagnosticData>?diagnosticsToFix, Func <Project, bool> shouldFixInProject, bool filterStaleDiagnostics, bool isAddSuppression, bool isSuppressionInSource, bool onlyCompilerDiagnostics, bool showPreviewChangesDialog) { try { using var token = _listener.BeginAsyncOperation(nameof(ApplySuppressionFix)); var title = GetFixTitle(isAddSuppression); var waitDialogMessage = GetWaitDialogMessage(isAddSuppression); using var context = _uiThreadOperationExecutor.BeginExecute( title, waitDialogMessage, allowCancellation: true, showProgress: true); if (diagnosticsToFix == null) { return; } diagnosticsToFix = FilterDiagnostics(diagnosticsToFix, isAddSuppression, isSuppressionInSource, onlyCompilerDiagnostics); if (diagnosticsToFix.IsEmpty()) { return; } var newSolution = _workspace.CurrentSolution; var cancellationToken = context.UserCancellationToken; cancellationToken.ThrowIfCancellationRequested(); var documentDiagnosticsToFixMap = await GetDocumentDiagnosticsToFixAsync( diagnosticsToFix, shouldFixInProject, filterStaleDiagnostics, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); var projectDiagnosticsToFixMap = isSuppressionInSource ? ImmutableDictionary <Project, ImmutableArray <Diagnostic> > .Empty : await GetProjectDiagnosticsToFixAsync(diagnosticsToFix, shouldFixInProject, filterStaleDiagnostics, cancellationToken).ConfigureAwait(false); if (documentDiagnosticsToFixMap == null || projectDiagnosticsToFixMap == null || (documentDiagnosticsToFixMap.IsEmpty && projectDiagnosticsToFixMap.IsEmpty)) { // Nothing to fix. return; } cancellationToken.ThrowIfCancellationRequested(); // Equivalence key determines what fix will be applied. // Make sure we don't include any specific diagnostic ID, as we want all of the given diagnostics (which can have varied ID) to be fixed. var equivalenceKey = isAddSuppression ? (isSuppressionInSource ? FeaturesResources.in_Source : FeaturesResources.in_Suppression_File) : FeaturesResources.Remove_Suppression; // We have different suppression fixers for every language. // So we need to group diagnostics by the containing project language and apply fixes separately. var languages = new HashSet <string>(projectDiagnosticsToFixMap.Select(p => p.Key.Language).Concat(documentDiagnosticsToFixMap.Select(kvp => kvp.Key.Project.Language))); foreach (var language in languages) { // Use the Fix multiple occurrences service to compute a bulk suppression fix for the specified document and project diagnostics, // show a preview changes dialog and then apply the fix to the workspace. cancellationToken.ThrowIfCancellationRequested(); var options = _globalOptions.GetCodeActionOptions(language); var optionsProvider = new CodeActionOptionsProvider(_ => options); var documentDiagnosticsPerLanguage = GetDocumentDiagnosticsMappedToNewSolution(documentDiagnosticsToFixMap, newSolution, language); if (!documentDiagnosticsPerLanguage.IsEmpty) { var suppressionFixer = GetSuppressionFixer(documentDiagnosticsPerLanguage.SelectMany(kvp => kvp.Value), language, _codeFixService); if (suppressionFixer != null) { var suppressionFixAllProvider = suppressionFixer.GetFixAllProvider(); newSolution = _fixMultipleOccurencesService.GetFix( documentDiagnosticsPerLanguage, _workspace, suppressionFixer, suppressionFixAllProvider, optionsProvider, equivalenceKey, title, waitDialogMessage, cancellationToken); if (newSolution == null) { // User cancelled or fixer threw an exception, so we just bail out. return; } } } var projectDiagnosticsPerLanguage = GetProjectDiagnosticsMappedToNewSolution(projectDiagnosticsToFixMap, newSolution, language); if (!projectDiagnosticsPerLanguage.IsEmpty) { var suppressionFixer = GetSuppressionFixer(projectDiagnosticsPerLanguage.SelectMany(kvp => kvp.Value), language, _codeFixService); if (suppressionFixer != null) { var suppressionFixAllProvider = suppressionFixer.GetFixAllProvider(); newSolution = _fixMultipleOccurencesService.GetFix( projectDiagnosticsPerLanguage, _workspace, suppressionFixer, suppressionFixAllProvider, optionsProvider, equivalenceKey, title, waitDialogMessage, cancellationToken); if (newSolution == null) { return; } } } if (newSolution == _workspace.CurrentSolution) { // No changes. return; } if (showPreviewChangesDialog) { newSolution = FixAllGetFixesService.PreviewChanges( _workspace.CurrentSolution, newSolution, fixAllPreviewChangesTitle: title, fixAllTopLevelHeader: title, languageOpt: languages?.Count == 1 ? languages.Single() : null, workspace: _workspace); if (newSolution == null) { return; } } waitDialogMessage = isAddSuppression ? ServicesVSResources.Applying_suppressions_fix : ServicesVSResources.Applying_remove_suppressions_fix; var operations = ImmutableArray.Create <CodeActionOperation>(new ApplyChangesOperation(newSolution)); using var scope = context.AddScope(allowCancellation: true, description: waitDialogMessage); await _editHandlerService.ApplyAsync( _workspace, fromDocument : null, operations : operations, title : title, progressTracker : new UIThreadOperationContextProgressTracker(scope), cancellationToken : cancellationToken).ConfigureAwait(false); // Kick off diagnostic re-analysis for affected projects so that diagnostics gets refreshed. _ = Task.Run(() => { var reanalyzeDocuments = diagnosticsToFix.Select(d => d.DocumentId).WhereNotNull().Distinct(); _diagnosticService.Reanalyze(_workspace, documentIds: reanalyzeDocuments, highPriority: true); }); } } catch (OperationCanceledException) { } catch (Exception ex) when(FatalError.ReportAndCatch(ex)) { } }
protected override async Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider options, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); foreach (var diagnostic in diagnostics) { var node = root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true); editor.ReplaceNode(node, (n, _) => { if (!syntaxFacts.IsBinaryExpression(n)) { // This should happen only in error cases. return(n); } syntaxFacts.GetPartsOfBinaryExpression(n, out var left, out var right); if (diagnostic.Properties[RedundantEqualityConstants.RedundantSide] == RedundantEqualityConstants.Right) { return(WithElasticTrailingTrivia(left)); } else if (diagnostic.Properties[RedundantEqualityConstants.RedundantSide] == RedundantEqualityConstants.Left) { return(WithElasticTrailingTrivia(right)); } return(n); });
protected override async Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider options, CancellationToken cancellationToken) { var formattingOptions = await GetOptionsAsync(document, cancellationToken).ConfigureAwait(false); var updatedRoot = Formatter.Format(editor.OriginalRoot, SyntaxFormatting, formattingOptions, cancellationToken); editor.ReplaceNode(editor.OriginalRoot, updatedRoot); }
public static Task <ImmutableArray <CodeRefactoring> > GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CodeActionOptionsProvider options, bool isBlocking, CancellationToken cancellationToken) => service.GetRefactoringsAsync(document, state, CodeActionRequestPriority.None, options, isBlocking, addOperationScope: _ => null, cancellationToken);
protected override Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider options, CancellationToken cancellationToken) { foreach (var diagnostic in diagnostics) { var node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan); editor.RemoveNode(node); } return(Task.CompletedTask); }
public AddNewKeywordAction(Document document, SyntaxNode node, CodeActionOptionsProvider fallbackOptions) { _document = document; _node = node; _fallbackOptions = fallbackOptions; }
protected override async Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { string? newLine = null; SourceText?sourceText = null; foreach (var diagnostic in diagnostics) { var node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan); if (node.IsKind(SyntaxKind.VariableDeclarator) && !(node = node.Parent?.Parent).IsKind(SyntaxKind.EventFieldDeclaration)) { continue; } #if CODE_STYLE var optionSet = document.Project.AnalyzerOptions.GetAnalyzerOptionSet(node.SyntaxTree, cancellationToken); #else var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); #endif newLine ??= optionSet.GetOption(FormattingOptions2.NewLine); // We can safely assume, that there is no leading doc comment, because that is what CS1591 is telling us. // So we create a new /// <inheritdoc/> comment. var xmlSpaceAfterTripleSlash = Token(leading: TriviaList(DocumentationCommentExterior("///")), SyntaxKind.XmlTextLiteralToken, text: " ", valueText: " ", trailing: default);
public Task <ImmutableArray <CodeFix> > GetFixesAsync( Document document, TextSpan span, IEnumerable <Diagnostic> diagnostics, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { return(GetSuppressionsAsync(document, span, diagnostics, fallbackOptions, skipSuppressMessage: false, skipUnsuppress: false, cancellationToken: cancellationToken)); }
/// <summary> /// Checks if we should wrap the conditional expression over multiple lines. /// </summary> private static async Task <bool> MakeMultiLineAsync( Document document, SyntaxNode condition, SyntaxNode trueSyntax, SyntaxNode falseSyntax, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); if (!sourceText.AreOnSameLine(condition.GetFirstToken(), condition.GetLastToken()) || !sourceText.AreOnSameLine(trueSyntax.GetFirstToken(), trueSyntax.GetLastToken()) || !sourceText.AreOnSameLine(falseSyntax.GetFirstToken(), falseSyntax.GetLastToken())) { return(true); } // the option is currently not an editorconfig option, so not available in code style layer var wrappingLength = #if !CODE_STYLE fallbackOptions.GetOptions(document.Project.LanguageServices)?.ConditionalExpressionWrappingLength ?? #endif CodeActionOptions.DefaultConditionalExpressionWrappingLength; if (condition.Span.Length + trueSyntax.Span.Length + falseSyntax.Span.Length > wrappingLength) { return(true); } return(false); }
internal async Task <ImmutableArray <PragmaWarningCodeAction> > GetPragmaSuppressionsAsync(Document document, TextSpan span, IEnumerable <Diagnostic> diagnostics, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var codeFixes = await GetSuppressionsAsync(document, span, diagnostics, fallbackOptions, skipSuppressMessage : true, skipUnsuppress : true, cancellationToken : cancellationToken).ConfigureAwait(false); return(codeFixes.SelectMany(fix => fix.Action.NestedCodeActions) .OfType <PragmaWarningCodeAction>() .ToImmutableArray()); }
public static async Task <Document> FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, CodeActionOptionsProvider codeActionOptionsProvider, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); var options = await document.GetCSharpCodeFixOptionsProviderAsync(codeActionOptionsProvider, cancellationToken).ConfigureAwait(false); var endOfLineTrivia = SyntaxFactory.ElasticEndOfLine(options.NewLine); foreach (var diagnostic in diagnostics) { FixOne(editor, diagnostic, endOfLineTrivia, cancellationToken); } return(document.WithSyntaxRoot(editor.GetChangedRoot())); }
private async Task <ImmutableArray <CodeFix> > GetSuppressionsAsync( Document documentOpt, Project project, IEnumerable <Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, CodeActionOptionsProvider fallbackOptions, bool skipSuppressMessage, bool skipUnsuppress, CancellationToken cancellationToken) { // We only care about diagnostics that can be suppressed/unsuppressed. diagnostics = diagnostics.Where(IsFixableDiagnostic); if (diagnostics.IsEmpty()) { return(ImmutableArray <CodeFix> .Empty); } INamedTypeSymbol suppressMessageAttribute = null; if (!skipSuppressMessage) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); suppressMessageAttribute = compilation.SuppressMessageAttributeType(); skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute(); } var lazyFormattingOptions = (SyntaxFormattingOptions)null; var result = ArrayBuilder <CodeFix> .GetInstance(); foreach (var diagnostic in diagnostics) { if (!diagnostic.IsSuppressed) { var nestedActions = ArrayBuilder <NestedSuppressionCodeAction> .GetInstance(); if (diagnostic.Location.IsInSource && documentOpt != null) { // pragma warning disable. lazyFormattingOptions ??= await documentOpt.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, lazyFormattingOptions, diagnostic, this)); } // SuppressMessageAttribute suppression is not supported for compiler diagnostics. if (!skipSuppressMessage && SuppressionHelpers.CanBeSuppressedWithAttribute(diagnostic)) { // global assembly-level suppress message attribute. nestedActions.Add(new GlobalSuppressMessageCodeAction( suppressionTargetInfo.TargetSymbol, suppressMessageAttribute, project, diagnostic, this, fallbackOptions)); // local suppress message attribute // please note that in order to avoid issues with existing unit tests referencing the code fix // by their index this needs to be the last added to nestedActions if (suppressionTargetInfo.TargetMemberNode != null && suppressionTargetInfo.TargetSymbol.Kind != SymbolKind.Namespace) { nestedActions.Add(new LocalSuppressMessageCodeAction( this, suppressionTargetInfo.TargetSymbol, suppressMessageAttribute, suppressionTargetInfo.TargetMemberNode, documentOpt, diagnostic)); } } if (nestedActions.Count > 0) { var codeAction = new TopLevelSuppressionCodeAction( diagnostic, nestedActions.ToImmutableAndFree()); result.Add(new CodeFix(project, codeAction, diagnostic)); } } else if (!skipUnsuppress) { var codeAction = await RemoveSuppressionCodeAction.CreateAsync(suppressionTargetInfo, documentOpt, project, diagnostic, this, fallbackOptions, cancellationToken).ConfigureAwait(false); if (codeAction != null) { result.Add(new CodeFix(project, codeAction, diagnostic)); } } } return(result.ToImmutableAndFree()); }
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var fixedDocument = await ConvertToProgramMainAsync(document, cancellationToken).ConfigureAwait(false); var fixedRoot = await fixedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); editor.ReplaceNode(editor.OriginalRoot, fixedRoot); }
protected override async Task FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var options = await document.GetAnalyzerOptionsProviderAsync(cancellationToken).ConfigureAwait(false); var option = GetCodeStyleOption(options); if (!_helpers.TryGetOrComputePreferredOrder(option.Value, out var preferredOrder)) { return; } foreach (var diagnostic in diagnostics) { var memberDeclaration = diagnostic.Location.FindNode(cancellationToken); editor.ReplaceNode(memberDeclaration, (currentNode, _) => { var modifiers = _syntaxFacts.GetModifiers(currentNode); var orderedModifiers = new SyntaxTokenList( modifiers.OrderBy(CompareModifiers) .Select((t, i) => t.WithTriviaFrom(modifiers[i]))); var updatedMemberDeclaration = _syntaxFacts.WithModifiers(currentNode, orderedModifiers); return(updatedMemberDeclaration); }); } return; // Local functions int CompareModifiers(SyntaxToken t1, SyntaxToken t2) => GetOrder(t1) - GetOrder(t2); int GetOrder(SyntaxToken token) => preferredOrder.TryGetValue(token.RawKind, out var value) ? value : int.MaxValue; }
public static async ValueTask <CSharpCodeFixOptionsProvider> GetCSharpCodeFixOptionsProviderAsync(this Document document, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); return(new CSharpCodeFixOptionsProvider(configOptions, fallbackOptions, document.Project.GetExtendedLanguageServices())); }
private async Task <Document> ApplyCodeFixesForSpecificDiagnosticIdsAsync( Document document, ImmutableArray <string> diagnosticIds, IProgressTracker progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { foreach (var diagnosticId in diagnosticIds) { using (Logger.LogBlock(FunctionId.CodeCleanup_ApplyCodeFixesAsync, diagnosticId, cancellationToken)) { document = await ApplyCodeFixesForSpecificDiagnosticIdAsync( document, diagnosticId, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); } } return(document); }
public static IAsyncEnumerable <CodeFixCollection> StreamFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptionsProvider fallbackOptions, bool isBlocking, CancellationToken cancellationToken) => service.StreamFixesAsync(document, range, CodeActionRequestPriority.None, fallbackOptions, isBlocking, addOperationScope: _ => null, cancellationToken);
private async Task <Document> ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var textSpan = new TextSpan(0, tree.Length); var fixCollection = await _codeFixService.GetDocumentFixAllForIdInSpanAsync( document, textSpan, diagnosticId, fallbackOptions, cancellationToken).ConfigureAwait(false); if (fixCollection == null) { return(document); } var fixAllService = document.Project.Solution.Workspace.Services.GetRequiredService <IFixAllGetFixesService>(); var solution = await fixAllService.GetFixAllChangedSolutionAsync( new FixAllContext(fixCollection.FixAllState, progressTracker, cancellationToken)).ConfigureAwait(false); return(solution.GetDocument(document.Id) ?? throw new NotSupportedException(FeaturesResources.Removal_of_document_not_supported)); }
public static Task <ImmutableArray <CodeFixCollection> > GetFixesAsync(this ICodeFixService service, Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptionsProvider fallbackOptions, bool isBlocking, Func <string, IDisposable?> addOperationScope, CancellationToken cancellationToken) => service.StreamFixesAsync(document, textSpan, priority, fallbackOptions, isBlocking, addOperationScope, cancellationToken).ToImmutableArrayAsync(cancellationToken);
private async Task <CodeRefactoring?> GetRefactoringFromProviderAsync( Document document, TextSpan state, CodeRefactoringProvider provider, CodeChangeProviderMetadata?providerMetadata, IExtensionManager extensionManager, CodeActionOptionsProvider options, bool isBlocking, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (extensionManager.IsDisabled(provider)) { return(null); } try { using var _ = ArrayBuilder <(CodeAction action, TextSpan?applicableToSpan)> .GetInstance(out var actions); var context = new CodeRefactoringContext(document, state, // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? (action, applicableToSpan) => { // Serialize access for thread safety - we don't know what thread the refactoring provider will call this delegate from. lock (actions) { // Add the Refactoring Provider Name to the parent CodeAction's CustomTags. // Always add a name even in cases of 3rd party refactorings that do not export // name metadata. action.AddCustomTagAndTelemetryInfo(providerMetadata, provider); actions.Add((action, applicableToSpan)); } }, options, isBlocking, cancellationToken); var task = provider.ComputeRefactoringsAsync(context) ?? Task.CompletedTask; await task.ConfigureAwait(false); if (actions.Count == 0) { return(null); } var fixAllProviderInfo = extensionManager.PerformFunction( provider, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, provider, FixAllProviderInfo.Create), defaultValue: null); return(new CodeRefactoring(provider, actions.ToImmutable(), fixAllProviderInfo, options)); } catch (OperationCanceledException) { // We don't want to catch operation canceled exceptions in the catch block // below. So catch is here and rethrow it. throw; } catch (Exception e) { extensionManager.HandleException(provider, e); } return(null); }