private static SyntaxToken GetNewStartToken(SyntaxToken startToken, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { var trivia = startToken.LeadingTrivia.ToImmutableArray(); // Insert the #pragma disable directive after all leading new line trivia but before first trivia of any other kind. int index; SyntaxTrivia firstNonEOLTrivia = trivia.FirstOrDefault(t => !fixer.IsEndOfLine(t)); if (firstNonEOLTrivia == default(SyntaxTrivia)) { index = trivia.Length; } else { index = trivia.IndexOf(firstNonEOLTrivia); } bool needsLeadingEOL; if (index > 0) { needsLeadingEOL = !fixer.IsEndOfLine(trivia[index - 1]); } else if (startToken.FullSpan.Start == 0) { needsLeadingEOL = false; } else { needsLeadingEOL = true; } var pragmaWarningTrivia = fixer.CreatePragmaDisableDirectiveTrivia(diagnostic, needsLeadingEOL); return startToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaWarningTrivia)); }
public static AttributeRemoveAction Create( AttributeData attribute, Project project, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { return new AttributeRemoveAction(attribute, project, diagnostic, fixer); }
protected RemoveSuppressionCodeAction( Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(fixer, title: string.Format(FeaturesResources.Remove_Suppression_0, diagnostic.Id)) { _diagnostic = diagnostic; _forFixMultipleContext = forFixMultipleContext; }
public LocalSuppressMessageCodeAction(AbstractSuppressionCodeFixProvider fixer, ISymbol targetSymbol, SyntaxNode targetNode, Document document, Diagnostic diagnostic) { _fixer = fixer; _targetSymbol = targetSymbol; _targetNode = targetNode; _document = document; _diagnostic = diagnostic; _title = FeaturesResources.SuppressWithLocalSuppressMessage; }
private PragmaRemoveAction( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(document, diagnostic, fixer, forFixMultipleContext) { _suppressionTargetInfo = suppressionTargetInfo; }
private AttributeRemoveAction( AttributeData attribute, Project project, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(diagnostic, fixer, forFixMultipleContext) { _project = project; _attribute = attribute; }
public static PragmaWarningCodeAction Create( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { // We need to normalize the leading trivia on start token to account for // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token). PragmaHelpers.NormalizeTriviaOnTokens(fixer, ref document, ref suppressionTargetInfo); return(new PragmaWarningCodeAction(suppressionTargetInfo, document, diagnostic, fixer)); }
private GlobalSuppressMessageFixAllCodeAction( AbstractSuppressionCodeFixProvider fixer, INamedTypeSymbol suppressMessageAttribute, IEnumerable <KeyValuePair <ISymbol, ImmutableArray <Diagnostic> > > diagnosticsBySymbol, Project project, CodeActionOptionsProvider fallbackOptions) : base(fixer, project) { _suppressMessageAttribute = suppressMessageAttribute; _diagnosticsBySymbol = diagnosticsBySymbol; _fallbackOptions = fallbackOptions; }
public GlobalSuppressMessageCodeAction( ISymbol targetSymbol, INamedTypeSymbol suppressMessageAttribute, Project project, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, CodeActionOptionsProvider fallbackOptions) : base(fixer, project) { _targetSymbol = targetSymbol; _suppressMessageAttribute = suppressMessageAttribute; _diagnostic = diagnostic; _fallbackOptions = fallbackOptions; }
public static PragmaWarningCodeAction Create( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { // We need to normalize the leading trivia on start token to account for // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token). PragmaHelpers.NormalizeTriviaOnTokens(fixer, ref document, ref suppressionTargetInfo); return new PragmaWarningCodeAction(suppressionTargetInfo, document, diagnostic, fixer); }
private PragmaWarningCodeAction( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(fixer, title: FeaturesResources.in_Source) { _suppressionTargetInfo = suppressionTargetInfo; _document = document; _diagnostic = diagnostic; _forFixMultipleContext = forFixMultipleContext; }
private static bool IsEndOfLineOrHasTrailingEndOfLine( SyntaxTrivia trivia, AbstractSuppressionCodeFixProvider fixer ) { return(fixer.IsEndOfLine(trivia) || ( trivia.HasStructure && fixer.IsEndOfLine( trivia.GetStructure().DescendantTrivia().LastOrDefault() ) )); }
protected RemoveSuppressionCodeAction( Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false ) : base( fixer, title: string.Format(FeaturesResources.Remove_Suppression_0, diagnostic.Id) ) { _diagnostic = diagnostic; _forFixMultipleContext = forFixMultipleContext; }
private PragmaRemoveAction( SuppressionTargetInfo suppressionTargetInfo, Document document, SyntaxFormattingOptions options, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(diagnostic, fixer, forFixMultipleContext) { _document = document; _options = options; _suppressionTargetInfo = suppressionTargetInfo; }
private PragmaWarningCodeAction( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(fixer, title: FeaturesResources.SuppressWithPragma) { _suppressionTargetInfo = suppressionTargetInfo; _document = document; _diagnostic = diagnostic; _forFixMultipleContext = forFixMultipleContext; }
internal static SyntaxToken GetNewStartTokenWithAddedPragma( SyntaxToken startToken, TextSpan currentDiagnosticSpan, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, Func <SyntaxNode, SyntaxNode> formatNode, bool isRemoveSuppression = false ) { var trivia = startToken.LeadingTrivia.ToImmutableArray(); var index = GetPositionForPragmaInsertion( trivia, currentDiagnosticSpan, fixer, isStartToken: true, triviaAtIndex: out var insertAfterTrivia ); index++; bool needsLeadingEOL; if (index > 0) { needsLeadingEOL = !IsEndOfLineOrHasTrailingEndOfLine(insertAfterTrivia, fixer); } else if (startToken.FullSpan.Start == 0) { needsLeadingEOL = false; } else { needsLeadingEOL = true; } var pragmaTrivia = !isRemoveSuppression ? fixer.CreatePragmaDisableDirectiveTrivia( diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine : true ) : fixer.CreatePragmaRestoreDirectiveTrivia( diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true ); return(startToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaTrivia))); }
internal static async Task <SyntaxToken> GetNewEndTokenWithAddedPragmaAsync( SyntaxToken endToken, TextSpan currentDiagnosticSpan, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, Func <SyntaxNode, Task <SyntaxNode> > formatNode, bool isRemoveSuppression = false) { ImmutableArray <SyntaxTrivia> trivia; var isEOF = fixer.IsEndOfFileToken(endToken); if (isEOF) { trivia = endToken.LeadingTrivia.ToImmutableArray(); } else { trivia = endToken.TrailingTrivia.ToImmutableArray(); } SyntaxTrivia insertBeforeTrivia; var index = GetPositionForPragmaInsertion(trivia, currentDiagnosticSpan, fixer, isStartToken: false, triviaAtIndex: out insertBeforeTrivia); bool needsTrailingEOL; if (index < trivia.Length) { needsTrailingEOL = !IsEndOfLineOrHasLeadingEndOfLine(insertBeforeTrivia, fixer); } else if (isEOF) { needsTrailingEOL = false; } else { needsTrailingEOL = true; } var pragmaTrivia = !isRemoveSuppression ? await fixer.CreatePragmaRestoreDirectiveTriviaAsync(diagnostic, formatNode, needsLeadingEndOfLine : true, needsTrailingEndOfLine : needsTrailingEOL).ConfigureAwait(false) : await fixer.CreatePragmaDisableDirectiveTriviaAsync(diagnostic, formatNode, needsLeadingEndOfLine : true, needsTrailingEndOfLine : needsTrailingEOL).ConfigureAwait(false); if (isEOF) { return(endToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaTrivia))); } else { return(endToken.WithTrailingTrivia(trivia.InsertRange(index, pragmaTrivia))); }; }
internal static CodeAction Create( string title, AbstractSuppressionCodeFixProvider fixer, Project triggerProject, ImmutableDictionary <Project, ImmutableArray <Diagnostic> > diagnosticsByProject ) { return(new GlobalSuppressionSolutionChangeAction( title, ct => CreateChangedSolutionAsync(fixer, triggerProject, diagnosticsByProject, ct), equivalenceKey: title )); }
public static CodeAction CreateBatchPragmaFix( AbstractSuppressionCodeFixProvider suppressionFixProvider, Document document, ImmutableArray <IPragmaBasedCodeAction> pragmaActions, ImmutableArray <Diagnostic> pragmaDiagnostics, FixAllState fixAllState, CancellationToken cancellationToken) { return(CodeAction.Create( ((CodeAction)pragmaActions[0]).Title, createChangedDocument: ct => BatchPragmaFixesAsync(suppressionFixProvider, document, pragmaActions, pragmaDiagnostics, fixAllState.CodeActionOptionsProvider, cancellationToken), equivalenceKey: fixAllState.CodeActionEquivalenceKey)); }
public PragmaWarningCodeAction( AbstractSuppressionCodeFixProvider fixer, SyntaxToken startToken, SyntaxToken endToken, SyntaxNode nodeWithTokens, Document document, Diagnostic diagnostic) : base (fixer, title: FeaturesResources.SuppressWithPragma) { _startToken = startToken; _endToken = endToken; _nodeWithTokens = nodeWithTokens; _document = document; _diagnostic = diagnostic; }
public PragmaWarningCodeAction( AbstractSuppressionCodeFixProvider fixer, SyntaxToken startToken, SyntaxToken endToken, SyntaxNode nodeWithTokens, Document document, Diagnostic diagnostic) : base(fixer, title: FeaturesResources.SuppressWithPragma) { _startToken = startToken; _endToken = endToken; _nodeWithTokens = nodeWithTokens; _document = document; _diagnostic = diagnostic; }
public LocalSuppressMessageCodeAction( AbstractSuppressionCodeFixProvider fixer, ISymbol targetSymbol, INamedTypeSymbol suppressMessageAttribute, SyntaxNode targetNode, Document document, Diagnostic diagnostic) : base(fixer, FeaturesResources.in_Source_attribute) { _fixer = fixer; _targetSymbol = targetSymbol; _suppressMessageAttribute = suppressMessageAttribute; _targetNode = targetNode; _document = document; _diagnostic = diagnostic; }
public static CodeAction CreateBatchPragmaFix( AbstractSuppressionCodeFixProvider suppressionFixProvider, Document document, ImmutableArray<IPragmaBasedCodeAction> pragmaActions, ImmutableArray<Diagnostic> pragmaDiagnostics, FixAllContext fixAllContext) { // This is a temporary generated code action, which doesn't need telemetry, hence suppressing RS0005. #pragma warning disable RS0005 // Do not use generic CodeAction.Create to create CodeAction return CodeAction.Create( ((CodeAction)pragmaActions[0]).Title, createChangedDocument: ct => BatchPragmaFixesAsync(suppressionFixProvider, document, pragmaActions, pragmaDiagnostics, fixAllContext.CancellationToken), equivalenceKey: fixAllContext.CodeActionEquivalenceKey); #pragma warning restore RS0005 // Do not use generic CodeAction.Create to create CodeAction }
private static async Task <Solution> CreateChangedSolutionAsync( AbstractSuppressionCodeFixProvider fixer, Document triggerDocument, ImmutableDictionary <Document, ImmutableArray <Diagnostic> > diagnosticsByDocument, CancellationToken cancellationToken ) { var currentSolution = triggerDocument.Project.Solution; foreach (var grouping in diagnosticsByDocument.GroupBy(d => d.Key.Project)) { var oldProject = grouping.Key; var currentProject = currentSolution.GetProject(oldProject.Id); var compilation = await currentProject .GetCompilationAsync(cancellationToken) .ConfigureAwait(false); var supressMessageAttribute = compilation.SuppressMessageAttributeType(); if (supressMessageAttribute != null) { var diagnosticsBySymbol = await CreateDiagnosticsBySymbolAsync( fixer, grouping, cancellationToken ) .ConfigureAwait(false); if (diagnosticsBySymbol.Any()) { var projectCodeAction = new GlobalSuppressMessageFixAllCodeAction( fixer, supressMessageAttribute, diagnosticsBySymbol, currentProject ); var newDocument = await projectCodeAction .GetChangedSuppressionDocumentAsync(cancellationToken) .ConfigureAwait(false); currentSolution = newDocument.Project.Solution; } } } return(currentSolution); }
public PragmaWarningCodeAction( AbstractSuppressionCodeFixProvider fixer, SyntaxToken startToken, SyntaxToken endToken, SyntaxNode nodeWithTokens, Document document, Diagnostic diagnostic) { _fixer = fixer; _startToken = startToken; _endToken = endToken; _nodeWithTokens = nodeWithTokens; _document = document; _diagnostic = diagnostic; _title = fixer.TitleForPragmaWarningSuppressionFix; }
public static CodeAction CreateBatchPragmaFix( AbstractSuppressionCodeFixProvider suppressionFixProvider, Document document, ImmutableArray <IPragmaBasedCodeAction> pragmaActions, ImmutableArray <Diagnostic> pragmaDiagnostics, FixAllContext fixAllContext) { // This is a temporary generated code action, which doesn't need telemetry, hence suppressing RS0005. #pragma warning disable RS0005 // Do not use generic CodeAction.Create to create CodeAction return(CodeAction.Create( ((CodeAction)pragmaActions[0]).Title, createChangedDocument: ct => BatchPragmaFixesAsync(suppressionFixProvider, document, pragmaActions, pragmaDiagnostics, fixAllContext.CancellationToken), equivalenceKey: fixAllContext.CodeActionEquivalenceKey)); #pragma warning restore RS0005 // Do not use generic CodeAction.Create to create CodeAction }
public static async Task<RemoveSuppressionCodeAction> CreateAsync( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, CancellationToken cancellationToken) { var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var attribute = diagnostic.GetSuppressionInfo(compilation).Attribute; if (attribute != null) { return AttributeRemoveAction.Create(attribute, document, diagnostic, fixer); } else { return PragmaRemoveAction.Create(suppressionTargetInfo, document, diagnostic, fixer); } }
private static async Task<Solution> CreateChangedSolutionAsync(AbstractSuppressionCodeFixProvider fixer, Project triggerProject, ImmutableDictionary<Project, ImmutableArray<Diagnostic>> diagnosticsByProject, CancellationToken cancellationToken) { var currentSolution = triggerProject.Solution; foreach (var kvp in diagnosticsByProject) { var oldProject = kvp.Key; var currentProject = currentSolution.GetProject(oldProject.Id); var diagnosticsBySymbol = await CreateDiagnosticsBySymbolAsync(fixer, oldProject, kvp.Value, cancellationToken).ConfigureAwait(false); if (diagnosticsBySymbol.Any()) { var projectCodeAction = new GlobalSuppressMessageFixAllCodeAction(fixer, diagnosticsBySymbol, currentProject); var newDocument = await projectCodeAction.GetChangedSuppressionDocumentAsync(cancellationToken).ConfigureAwait(false); currentSolution = newDocument.Project.Solution; } } return currentSolution; }
private static int GetPositionForPragmaInsertion( ImmutableArray <SyntaxTrivia> triviaList, TextSpan currentDiagnosticSpan, AbstractSuppressionCodeFixProvider fixer, bool isStartToken, out SyntaxTrivia triviaAtIndex ) { // Start token: Insert the #pragma disable directive just **before** the first end of line trivia prior to diagnostic location. // End token: Insert the #pragma disable directive just **after** the first end of line trivia after diagnostic location. int getNextIndex(int cur) => isStartToken ? cur - 1 : cur + 1; bool shouldConsiderTrivia(SyntaxTrivia trivia) => isStartToken ? trivia.FullSpan.End <= currentDiagnosticSpan.Start : trivia.FullSpan.Start >= currentDiagnosticSpan.End; var walkedPastDiagnosticSpan = false; var seenEndOfLineTrivia = false; var index = isStartToken ? triviaList.Length - 1 : 0; while (index >= 0 && index < triviaList.Length) { var trivia = triviaList[index]; walkedPastDiagnosticSpan = walkedPastDiagnosticSpan || shouldConsiderTrivia(trivia); seenEndOfLineTrivia = seenEndOfLineTrivia || IsEndOfLineOrContainsEndOfLine(trivia, fixer); if (walkedPastDiagnosticSpan && seenEndOfLineTrivia) { break; } index = getNextIndex(index); } triviaAtIndex = index >= 0 && index < triviaList.Length ? triviaList[index] : default; return(index); }
> CreateDiagnosticsBySymbolAsync( AbstractSuppressionCodeFixProvider fixer, IEnumerable < KeyValuePair <Document, ImmutableArray <Diagnostic> > > diagnosticsByDocument, CancellationToken cancellationToken ) { var diagnosticsMapBuilder = ImmutableDictionary.CreateBuilder < ISymbol, List <Diagnostic> >(); foreach (var(document, diagnostics) in diagnosticsByDocument) { foreach (var diagnostic in diagnostics) { Contract.ThrowIfFalse(diagnostic.Location.IsInSource); var suppressionTargetInfo = await fixer .GetSuppressionTargetInfoAsync( document, diagnostic.Location.SourceSpan, cancellationToken ) .ConfigureAwait(false); if (suppressionTargetInfo != null) { var targetSymbol = suppressionTargetInfo.TargetSymbol; Contract.ThrowIfNull(targetSymbol); AddDiagnosticForSymbolIfNeeded( targetSymbol, diagnostic, diagnosticsMapBuilder ); } } } return(CreateDiagnosticsBySymbol(diagnosticsMapBuilder)); }
private static async Task <Solution> CreateChangedSolutionAsync(AbstractSuppressionCodeFixProvider fixer, Project triggerProject, ImmutableDictionary <Project, ImmutableArray <Diagnostic> > diagnosticsByProject, CancellationToken cancellationToken) { var currentSolution = triggerProject.Solution; foreach (var kvp in diagnosticsByProject) { var oldProject = kvp.Key; var currentProject = currentSolution.GetProject(oldProject.Id); var diagnosticsBySymbol = await CreateDiagnosticsBySymbolAsync(fixer, oldProject, kvp.Value, cancellationToken).ConfigureAwait(false); if (diagnosticsBySymbol.Any()) { var projectCodeAction = new GlobalSuppressMessageFixAllCodeAction(fixer, diagnosticsBySymbol, currentProject); var newDocument = await projectCodeAction.GetChangedSuppressionDocumentAsync(cancellationToken).ConfigureAwait(false); currentSolution = newDocument.Project.Solution; } } return(currentSolution); }
private static async Task<IEnumerable<KeyValuePair<ISymbol, ImmutableArray<Diagnostic>>>> CreateDiagnosticsBySymbolAsync(AbstractSuppressionCodeFixProvider fixer, IEnumerable<KeyValuePair<Document, ImmutableArray<Diagnostic>>> diagnosticsByDocument, CancellationToken cancellationToken) { var diagnosticsMapBuilder = ImmutableDictionary.CreateBuilder<ISymbol, List<Diagnostic>>(); foreach (var kvp in diagnosticsByDocument) { var document = kvp.Key; var diagnostics = kvp.Value; foreach (var diagnostic in diagnostics) { Contract.ThrowIfFalse(diagnostic.Location.IsInSource); var suppressionTargetInfo = await fixer.GetSuppressionTargetInfoAsync(document, diagnostic.Location.SourceSpan, cancellationToken).ConfigureAwait(false); if (suppressionTargetInfo != null) { var targetSymbol = suppressionTargetInfo.TargetSymbol; Contract.ThrowIfNull(targetSymbol); AddDiagnosticForSymbolIfNeeded(targetSymbol, diagnostic, diagnosticsMapBuilder); } } } return CreateDiagnosticsBySymbol(diagnosticsMapBuilder); }
private static int GetPositionForPragmaInsertion(ImmutableArray<SyntaxTrivia> triviaList, TextSpan currentDiagnosticSpan, AbstractSuppressionCodeFixProvider fixer, bool isStartToken, out SyntaxTrivia triviaAtIndex) { // Start token: Insert the #pragma disable directive just **before** the first end of line trivia prior to diagnostic location. // End token: Insert the #pragma disable directive just **after** the first end of line trivia after diagnostic location. Func<int, int> getNextIndex = cur => isStartToken ? cur - 1 : cur + 1; Func<SyntaxTrivia, bool> shouldConsiderTrivia = trivia => isStartToken ? trivia.FullSpan.End <= currentDiagnosticSpan.Start : trivia.FullSpan.Start >= currentDiagnosticSpan.End; var walkedPastDiagnosticSpan = false; var seenEndOfLineTrivia = false; var index = isStartToken ? triviaList.Length - 1 : 0; while (index >= 0 && index < triviaList.Length) { var trivia = triviaList[index]; walkedPastDiagnosticSpan = walkedPastDiagnosticSpan || shouldConsiderTrivia(trivia); seenEndOfLineTrivia = seenEndOfLineTrivia || (fixer.IsEndOfLine(trivia) || (trivia.HasStructure && trivia.GetStructure().DescendantTrivia().Any(t => fixer.IsEndOfLine(t)))); if (walkedPastDiagnosticSpan && seenEndOfLineTrivia) { break; } index = getNextIndex(index); } triviaAtIndex = index >= 0 && index < triviaList.Length ? triviaList[index] : default(SyntaxTrivia); return index; }
public static async Task<RemoveSuppressionCodeAction> CreateAsync( SuppressionTargetInfo suppressionTargetInfo, Document documentOpt, Project project, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, CancellationToken cancellationToken) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var attribute = diagnostic.GetSuppressionInfo(compilation).Attribute; if (attribute != null) { return AttributeRemoveAction.Create(attribute, project, diagnostic, fixer); } else if (documentOpt != null && !SuppressionHelpers.IsSynthesizedExternalSourceDiagnostic(diagnostic)) { return PragmaRemoveAction.Create(suppressionTargetInfo, documentOpt, diagnostic, fixer); } else { return null; } }
public static BatchFixAllProvider GetBatchFixer(AbstractSuppressionCodeFixProvider suppressionFixProvider) { return(new BatchFixer(suppressionFixProvider)); }
public PragmaWarningBatchFixAllProvider(AbstractSuppressionCodeFixProvider suppressionFixProvider) { _suppressionFixProvider = suppressionFixProvider; }
internal static async Task<SyntaxToken> GetNewStartTokenWithAddedPragmaAsync( SyntaxToken startToken, TextSpan currentDiagnosticSpan, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, Func<SyntaxNode, Task<SyntaxNode>> formatNode, bool isRemoveSuppression = false) { var trivia = startToken.LeadingTrivia.ToImmutableArray(); SyntaxTrivia insertAfterTrivia; var index = GetPositionForPragmaInsertion(trivia, currentDiagnosticSpan, fixer, isStartToken: true, triviaAtIndex: out insertAfterTrivia); index++; bool needsLeadingEOL; if (index > 0) { needsLeadingEOL = !IsEndOfLineOrHasTrailingEndOfLine(insertAfterTrivia, fixer); } else if (startToken.FullSpan.Start == 0) { needsLeadingEOL = false; } else { needsLeadingEOL = true; } var pragmaTrivia = !isRemoveSuppression ? await fixer.CreatePragmaDisableDirectiveTriviaAsync(diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true).ConfigureAwait(false) : await fixer.CreatePragmaRestoreDirectiveTriviaAsync(diagnostic, formatNode, needsLeadingEOL, needsTrailingEndOfLine: true).ConfigureAwait(false); return startToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaTrivia)); }
private static SyntaxTriviaList GetTriviaListForSuppression(SyntaxToken token, bool isStartToken, AbstractSuppressionCodeFixProvider fixer) { return(isStartToken || fixer.IsEndOfFileToken(token) ? token.LeadingTrivia : token.TrailingTrivia); }
private GlobalSuppressMessageFixAllCodeAction(AbstractSuppressionCodeFixProvider fixer, IEnumerable <KeyValuePair <ISymbol, ImmutableArray <Diagnostic> > > diagnosticsBySymbol, Project project) : base(fixer, project) { _diagnosticsBySymbol = diagnosticsBySymbol; }
private static async Task <Document> BatchPragmaFixesAsync( AbstractSuppressionCodeFixProvider suppressionFixProvider, Document document, ImmutableArray <IPragmaBasedCodeAction> pragmaActions, ImmutableArray <Diagnostic> diagnostics, CancellationToken cancellationToken) { // We apply all the pragma suppression fixes sequentially. // At every application, we track the updated locations for remaining diagnostics in the document. var currentDiagnosticSpans = new Dictionary <Diagnostic, TextSpan>(); foreach (var diagnostic in diagnostics) { currentDiagnosticSpans.Add(diagnostic, diagnostic.Location.SourceSpan); } var currentDocument = document; for (int i = 0; i < pragmaActions.Length; i++) { var originalpragmaAction = pragmaActions[i]; var diagnostic = diagnostics[i]; // Get the diagnostic span for the diagnostic in latest document snapshot. TextSpan currentDiagnosticSpan; if (!currentDiagnosticSpans.TryGetValue(diagnostic, out currentDiagnosticSpan)) { // Diagnostic whose location conflicts with a prior fix. continue; } // Compute and apply pragma suppression fix. var currentTree = await currentDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var currentLocation = Location.Create(currentTree, currentDiagnosticSpan); diagnostic = Diagnostic.Create( id: diagnostic.Id, category: diagnostic.Descriptor.Category, message: diagnostic.GetMessage(), severity: diagnostic.Severity, defaultSeverity: diagnostic.DefaultSeverity, isEnabledByDefault: diagnostic.Descriptor.IsEnabledByDefault, warningLevel: diagnostic.WarningLevel, title: diagnostic.Descriptor.Title, description: diagnostic.Descriptor.Description, helpLink: diagnostic.Descriptor.HelpLinkUri, location: currentLocation, additionalLocations: diagnostic.AdditionalLocations, customTags: diagnostic.Descriptor.CustomTags, properties: diagnostic.Properties, isSuppressed: diagnostic.IsSuppressed); var newSuppressionFixes = await suppressionFixProvider.GetSuppressionsAsync(currentDocument, currentDiagnosticSpan, SpecializedCollections.SingletonEnumerable(diagnostic), cancellationToken).ConfigureAwait(false); var newSuppressionFix = newSuppressionFixes.SingleOrDefault(); if (newSuppressionFix != null) { var newPragmaAction = newSuppressionFix.Action as IPragmaBasedCodeAction ?? newSuppressionFix.Action.NestedCodeActions.OfType <IPragmaBasedCodeAction>().SingleOrDefault(); if (newPragmaAction != null) { // Get the text changes with pragma suppression add/removals. // Note: We do it one token at a time to ensure we get single text change in the new document, otherwise UpdateDiagnosticSpans won't function as expected. // Update the diagnostics spans based on the text changes. var startTokenChanges = await GetTextChangesAsync(newPragmaAction, currentDocument, diagnostics, currentDiagnosticSpans, includeStartTokenChange : true, includeEndTokenChange : false, cancellationToken : cancellationToken).ConfigureAwait(false); var endTokenChanges = await GetTextChangesAsync(newPragmaAction, currentDocument, diagnostics, currentDiagnosticSpans, includeStartTokenChange : false, includeEndTokenChange : true, cancellationToken : cancellationToken).ConfigureAwait(false); var currentText = await currentDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); var orderedChanges = startTokenChanges.Concat(endTokenChanges).OrderBy(change => change.Span).Distinct(); var newText = currentText.WithChanges(orderedChanges); currentDocument = currentDocument.WithText(newText); // Update the diagnostics spans based on the text changes. UpdateDiagnosticSpans(diagnostics, currentDiagnosticSpans, orderedChanges); } } } return(currentDocument); }
private static bool CanRemovePragmaTrivia(SyntaxToken token, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool isStartToken, out int indexOfTriviaToRemove) { indexOfTriviaToRemove = -1; var triviaList = GetTriviaListForSuppression(token, isStartToken, fixer); var diagnosticSpan = diagnostic.Location.SourceSpan; Func<SyntaxTrivia, bool> shouldIncludeTrivia = t => isStartToken ? t.FullSpan.End <= diagnosticSpan.Start : t.FullSpan.Start >= diagnosticSpan.End; var filteredTriviaList = triviaList.Where(shouldIncludeTrivia); if (isStartToken) { // Walk bottom up for leading trivia. filteredTriviaList = filteredTriviaList.Reverse(); } foreach (var trivia in filteredTriviaList) { bool isEnableDirective, hasMultipleIds; if (fixer.IsAnyPragmaDirectiveForId(trivia, diagnostic.Id, out isEnableDirective, out hasMultipleIds)) { if (hasMultipleIds) { // Handle only simple cases where we have a single pragma directive with single ID matching ours in the trivia. return false; } // We want to look for leading disable directive and trailing enable directive. if ((isStartToken && !isEnableDirective) || (!isStartToken && isEnableDirective)) { indexOfTriviaToRemove = triviaList.IndexOf(trivia); return true; } return false; } } return false; }
private static async Task<Document> BatchPragmaFixesAsync( AbstractSuppressionCodeFixProvider suppressionFixProvider, Document document, ImmutableArray<IPragmaBasedCodeAction> pragmaActions, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken) { // We apply all the pragma suppression fixes sequentially. // At every application, we track the updated locations for remaining diagnostics in the document. var currentDiagnosticSpans = new Dictionary<Diagnostic, TextSpan>(); foreach (var diagnostic in diagnostics) { currentDiagnosticSpans.Add(diagnostic, diagnostic.Location.SourceSpan); } var currentDocument = document; for (int i = 0; i < pragmaActions.Length; i++) { var originalpragmaAction = pragmaActions[i]; var diagnostic = diagnostics[i]; // Get the diagnostic span for the diagnostic in latest document snapshot. TextSpan currentDiagnosticSpan; if (!currentDiagnosticSpans.TryGetValue(diagnostic, out currentDiagnosticSpan)) { // Diagnostic whose location conflicts with a prior fix. continue; } // Compute and apply pragma suppression fix. var currentTree = await currentDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var currentLocation = Location.Create(currentTree, currentDiagnosticSpan); diagnostic = Diagnostic.Create( id: diagnostic.Id, category: diagnostic.Descriptor.Category, message: diagnostic.GetMessage(), severity: diagnostic.Severity, defaultSeverity: diagnostic.DefaultSeverity, isEnabledByDefault: diagnostic.Descriptor.IsEnabledByDefault, warningLevel: diagnostic.WarningLevel, title: diagnostic.Descriptor.Title, description: diagnostic.Descriptor.Description, helpLink: diagnostic.Descriptor.HelpLinkUri, location: currentLocation, additionalLocations: diagnostic.AdditionalLocations, customTags: diagnostic.Descriptor.CustomTags, properties: diagnostic.Properties, isSuppressed: diagnostic.IsSuppressed); var newSuppressionFixes = await suppressionFixProvider.GetSuppressionsAsync(currentDocument, currentDiagnosticSpan, SpecializedCollections.SingletonEnumerable(diagnostic), cancellationToken).ConfigureAwait(false); var newSuppressionFix = newSuppressionFixes.SingleOrDefault(); if (newSuppressionFix != null) { var newPragmaAction = newSuppressionFix.Action as IPragmaBasedCodeAction ?? newSuppressionFix.Action.GetCodeActions().OfType<IPragmaBasedCodeAction>().SingleOrDefault(); if (newPragmaAction != null) { // Get the text changes with pragma suppression add/removals. // Note: We do it one token at a time to ensure we get single text change in the new document, otherwise UpdateDiagnosticSpans won't function as expected. // Update the diagnostics spans based on the text changes. var startTokenChanges = await GetTextChangesAsync(newPragmaAction, currentDocument, diagnostics, currentDiagnosticSpans, includeStartTokenChange: true, includeEndTokenChange: false, cancellationToken: cancellationToken).ConfigureAwait(false); var endTokenChanges = await GetTextChangesAsync(newPragmaAction, currentDocument, diagnostics, currentDiagnosticSpans, includeStartTokenChange: false, includeEndTokenChange: true, cancellationToken: cancellationToken).ConfigureAwait(false); var currentText = await currentDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); var orderedChanges = startTokenChanges.Concat(endTokenChanges).OrderBy(change => change.Span).Distinct(); var newText = currentText.WithChanges(orderedChanges); currentDocument = currentDocument.WithText(newText); // Update the diagnostics spans based on the text changes. UpdateDiagnosticSpans(diagnostics, currentDiagnosticSpans, orderedChanges); } } } return currentDocument; }
private static SyntaxTriviaList GetTriviaListForSuppression(SyntaxToken token, bool isStartToken, AbstractSuppressionCodeFixProvider fixer) { return isStartToken || fixer.IsEndOfFileToken(token) ? token.LeadingTrivia : token.TrailingTrivia; }
public BatchFixer(AbstractSuppressionCodeFixProvider suppressionFixProvider) { _suppressionFixProvider = suppressionFixProvider; }
public static BatchFixAllProvider GetBatchFixer(AbstractSuppressionCodeFixProvider suppressionFixProvider) { return new BatchFixer(suppressionFixProvider); }
private static SyntaxToken GetNewTokenWithPragmaUnsuppress(SyntaxToken token, int indexOfTriviaToRemoveOrToggle, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool isStartToken, bool toggle) { Contract.ThrowIfFalse(indexOfTriviaToRemoveOrToggle >= 0); var triviaList = GetTriviaListForSuppression(token, isStartToken, fixer); if (toggle) { var triviaToToggle = triviaList.ElementAt(indexOfTriviaToRemoveOrToggle); Contract.ThrowIfFalse(triviaToToggle != default(SyntaxTrivia)); var toggledTrivia = fixer.TogglePragmaDirective(triviaToToggle); triviaList = triviaList.Replace(triviaToToggle, toggledTrivia); } else { triviaList = triviaList.RemoveAt(indexOfTriviaToRemoveOrToggle); } return UpdateTriviaList(token, isStartToken, triviaList, fixer); }
private static bool IsEndOfLineOrHasTrailingEndOfLine(SyntaxTrivia trivia, AbstractSuppressionCodeFixProvider fixer) { return fixer.IsEndOfLine(trivia) || (trivia.HasStructure && fixer.IsEndOfLine(trivia.GetStructure().DescendantTrivia().LastOrDefault())); }
private static SyntaxToken UpdateTriviaList(SyntaxToken token, bool isStartToken, SyntaxTriviaList triviaList, AbstractSuppressionCodeFixProvider fixer) { return isStartToken || fixer.IsEndOfFileToken(token) ? token.WithLeadingTrivia(triviaList) : token.WithTrailingTrivia(triviaList); }
internal static void NormalizeTriviaOnTokens(AbstractSuppressionCodeFixProvider fixer, ref Document document, ref SuppressionTargetInfo suppressionTargetInfo) { // For pragma suppression fixes, we need to normalize the leading trivia on start token to account for // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token). var startToken = suppressionTargetInfo.StartToken; var endToken = suppressionTargetInfo.EndToken; var nodeWithTokens = suppressionTargetInfo.NodeWithTokens; var startAndEndTokensAreSame = startToken == endToken; var isEndTokenEOF = fixer.IsEndOfFileToken(endToken); var previousOfStart = startToken.GetPreviousToken(includeZeroWidth: true); var nextOfEnd = !isEndTokenEOF?endToken.GetNextToken(includeZeroWidth : true) : default(SyntaxToken); if (!previousOfStart.HasTrailingTrivia && !nextOfEnd.HasLeadingTrivia) { return; } var root = nodeWithTokens.SyntaxTree.GetRoot(); var spanEnd = !isEndTokenEOF ? nextOfEnd.FullSpan.End : endToken.FullSpan.End; var subtreeRoot = root.FindNode(new TextSpan(previousOfStart.FullSpan.Start, spanEnd - previousOfStart.FullSpan.Start)); var currentStartToken = startToken; var currentEndToken = endToken; var newStartToken = startToken.WithLeadingTrivia(previousOfStart.TrailingTrivia.Concat(startToken.LeadingTrivia)); SyntaxToken newEndToken = currentEndToken; if (startAndEndTokensAreSame) { newEndToken = newStartToken; } newEndToken = newEndToken.WithTrailingTrivia(endToken.TrailingTrivia.Concat(nextOfEnd.LeadingTrivia)); var newPreviousOfStart = previousOfStart.WithTrailingTrivia(); var newNextOfEnd = nextOfEnd.WithLeadingTrivia(); var newSubtreeRoot = subtreeRoot.ReplaceTokens(new[] { startToken, previousOfStart, endToken, nextOfEnd }, (o, n) => { if (o == currentStartToken) { return(startAndEndTokensAreSame ? newEndToken : newStartToken); } else if (o == previousOfStart) { return(newPreviousOfStart); } else if (o == currentEndToken) { return(newEndToken); } else if (o == nextOfEnd) { return(newNextOfEnd); } else { return(n); } }); root = root.ReplaceNode(subtreeRoot, newSubtreeRoot); document = document.WithSyntaxRoot(root); suppressionTargetInfo.StartToken = root.FindToken(startToken.SpanStart); suppressionTargetInfo.EndToken = root.FindToken(endToken.SpanStart); suppressionTargetInfo.NodeWithTokens = fixer.GetNodeWithTokens(suppressionTargetInfo.StartToken, suppressionTargetInfo.EndToken, root); }
private static bool IsEndOfLineOrContainsEndOfLine(SyntaxTrivia trivia, AbstractSuppressionCodeFixProvider fixer) { return fixer.IsEndOfLine(trivia) || (trivia.HasStructure && trivia.GetStructure().DescendantTrivia().Any(t => fixer.IsEndOfLine(t))); }
public GlobalSuppressMessageCodeAction(ISymbol targetSymbol, Project project, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) : base(fixer, project) { _targetSymbol = targetSymbol; _diagnostic = diagnostic; }
internal static async Task<SyntaxToken> GetNewEndTokenWithAddedPragmaAsync( SyntaxToken endToken, TextSpan currentDiagnosticSpan, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, Func<SyntaxNode, Task<SyntaxNode>> formatNode, bool isRemoveSuppression = false) { ImmutableArray<SyntaxTrivia> trivia; var isEOF = fixer.IsEndOfFileToken(endToken); if (isEOF) { trivia = endToken.LeadingTrivia.ToImmutableArray(); } else { trivia = endToken.TrailingTrivia.ToImmutableArray(); } SyntaxTrivia insertBeforeTrivia; var index = GetPositionForPragmaInsertion(trivia, currentDiagnosticSpan, fixer, isStartToken: false, triviaAtIndex: out insertBeforeTrivia); bool needsTrailingEOL; if (index < trivia.Length) { needsTrailingEOL = !IsEndOfLineOrHasLeadingEndOfLine(insertBeforeTrivia, fixer); } else if (isEOF) { needsTrailingEOL = false; } else { needsTrailingEOL = true; } var pragmaTrivia = !isRemoveSuppression ? await fixer.CreatePragmaRestoreDirectiveTriviaAsync(diagnostic, formatNode, needsLeadingEndOfLine: true, needsTrailingEndOfLine: needsTrailingEOL).ConfigureAwait(false) : await fixer.CreatePragmaDisableDirectiveTriviaAsync(diagnostic, formatNode, needsLeadingEndOfLine: true, needsTrailingEndOfLine: needsTrailingEOL).ConfigureAwait(false); if (isEOF) { return endToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaTrivia)); } else { return endToken.WithTrailingTrivia(trivia.InsertRange(index, pragmaTrivia)); }; }
private static async Task <IEnumerable <KeyValuePair <ISymbol, ImmutableArray <Diagnostic> > > > CreateDiagnosticsBySymbolAsync(AbstractSuppressionCodeFixProvider fixer, Project project, ImmutableArray <Diagnostic> diagnostics, CancellationToken cancellationToken) { var diagnosticsMapBuilder = ImmutableDictionary.CreateBuilder <ISymbol, List <Diagnostic> >(); var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); if (compilation != null) { foreach (var diagnostic in diagnostics) { Contract.ThrowIfFalse(!diagnostic.Location.IsInSource); var targetSymbol = compilation.Assembly; AddDiagnosticForSymbolIfNeeded(targetSymbol, diagnostic, diagnosticsMapBuilder); } } return(CreateDiagnosticsBySymbol(diagnosticsMapBuilder)); }
internal static void NormalizeTriviaOnTokens(AbstractSuppressionCodeFixProvider fixer, ref Document document, ref SuppressionTargetInfo suppressionTargetInfo) { // For pragma suppression fixes, we need to normalize the leading trivia on start token to account for // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token). var startToken = suppressionTargetInfo.StartToken; var endToken = suppressionTargetInfo.EndToken; var nodeWithTokens = suppressionTargetInfo.NodeWithTokens; var startAndEndTokensAreSame = startToken == endToken; var isEndTokenEOF = fixer.IsEndOfFileToken(endToken); var previousOfStart = startToken.GetPreviousToken(includeZeroWidth: true); var nextOfEnd = !isEndTokenEOF ? endToken.GetNextToken(includeZeroWidth: true) : default(SyntaxToken); if (!previousOfStart.HasTrailingTrivia && !nextOfEnd.HasLeadingTrivia) { return; } var root = nodeWithTokens.SyntaxTree.GetRoot(); var spanEnd = !isEndTokenEOF ? nextOfEnd.FullSpan.End : endToken.FullSpan.End; var subtreeRoot = root.FindNode(new TextSpan(previousOfStart.FullSpan.Start, spanEnd - previousOfStart.FullSpan.Start)); var currentStartToken = startToken; var currentEndToken = endToken; var newStartToken = startToken.WithLeadingTrivia(previousOfStart.TrailingTrivia.Concat(startToken.LeadingTrivia)); SyntaxToken newEndToken = currentEndToken; if (startAndEndTokensAreSame) { newEndToken = newStartToken; } newEndToken = newEndToken.WithTrailingTrivia(endToken.TrailingTrivia.Concat(nextOfEnd.LeadingTrivia)); var newPreviousOfStart = previousOfStart.WithTrailingTrivia(); var newNextOfEnd = nextOfEnd.WithLeadingTrivia(); var newSubtreeRoot = subtreeRoot.ReplaceTokens(new[] { startToken, previousOfStart, endToken, nextOfEnd }, (o, n) => { if (o == currentStartToken) { return startAndEndTokensAreSame ? newEndToken : newStartToken; } else if (o == previousOfStart) { return newPreviousOfStart; } else if (o == currentEndToken) { return newEndToken; } else if (o == nextOfEnd) { return newNextOfEnd; } else { return n; } }); root = root.ReplaceNode(subtreeRoot, newSubtreeRoot); document = document.WithSyntaxRoot(root); suppressionTargetInfo.StartToken = root.FindToken(startToken.SpanStart); suppressionTargetInfo.EndToken = root.FindToken(endToken.SpanStart); suppressionTargetInfo.NodeWithTokens = fixer.GetNodeWithTokens(suppressionTargetInfo.StartToken, suppressionTargetInfo.EndToken, root); }
private static SyntaxToken GetNewTokenWithPragmaUnsuppress(SyntaxToken token, int indexOfTriviaToRemoveOrToggle, AbstractSuppressionCodeFixProvider fixer, bool isStartToken, bool toggle) { Contract.ThrowIfFalse(indexOfTriviaToRemoveOrToggle >= 0); var triviaList = GetTriviaListForSuppression(token, isStartToken, fixer); if (toggle) { var triviaToToggle = triviaList.ElementAt(indexOfTriviaToRemoveOrToggle); Contract.ThrowIfFalse(triviaToToggle != default); var toggledTrivia = fixer.TogglePragmaDirective(triviaToToggle); triviaList = triviaList.Replace(triviaToToggle, toggledTrivia); } else { triviaList = triviaList.RemoveAt(indexOfTriviaToRemoveOrToggle); } return(UpdateTriviaList(token, isStartToken, triviaList, fixer)); }