public async Task <ImmutableArray <CodeFix> > GetFixesAsync( Project project, IEnumerable <Diagnostic> diagnostics, CancellationToken cancellationToken ) { if (!project.SupportsCompilation) { return(ImmutableArray <CodeFix> .Empty); } var compilation = await project .GetCompilationAsync(cancellationToken) .ConfigureAwait(false); var suppressionTargetInfo = new SuppressionTargetInfo() { TargetSymbol = compilation.Assembly }; return(await GetSuppressionsAsync( documentOpt : null, project : project, diagnostics : diagnostics, suppressionTargetInfo : suppressionTargetInfo, skipSuppressMessage : false, skipUnsuppress : false, cancellationToken : cancellationToken ) .ConfigureAwait(false)); }
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); } }
internal static async Task <Document> GetChangeDocumentWithPragmaAdjustedAsync( Document document, TextSpan diagnosticSpan, SuppressionTargetInfo suppressionTargetInfo, Func <SyntaxToken, TextSpan, SyntaxToken> getNewStartToken, Func <SyntaxToken, TextSpan, SyntaxToken> getNewEndToken, CancellationToken cancellationToken ) { var startToken = suppressionTargetInfo.StartToken; var endToken = suppressionTargetInfo.EndToken; var nodeWithTokens = suppressionTargetInfo.NodeWithTokens; var root = await nodeWithTokens.SyntaxTree .GetRootAsync(cancellationToken) .ConfigureAwait(false); var startAndEndTokenAreTheSame = startToken == endToken; var newStartToken = getNewStartToken(startToken, diagnosticSpan); var newEndToken = endToken; if (startAndEndTokenAreTheSame) { var annotation = new SyntaxAnnotation(); newEndToken = root.ReplaceToken( startToken, newStartToken.WithAdditionalAnnotations(annotation) ) .GetAnnotatedTokens(annotation) .Single(); var spanChange = newStartToken.LeadingTrivia.FullSpan.Length - startToken.LeadingTrivia.FullSpan.Length; diagnosticSpan = new TextSpan( diagnosticSpan.Start + spanChange, diagnosticSpan.Length ); } newEndToken = getNewEndToken(newEndToken, diagnosticSpan); SyntaxNode newNode; if (startAndEndTokenAreTheSame) { newNode = nodeWithTokens.ReplaceToken(startToken, newEndToken); } else { newNode = nodeWithTokens.ReplaceTokens( new[] { startToken, endToken }, (o, n) => o == startToken ? newStartToken : newEndToken ); } var newRoot = root.ReplaceNode(nodeWithTokens, newNode); return(document.WithSyntaxRoot(newRoot)); }
private PragmaRemoveAction( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(document, diagnostic, fixer, forFixMultipleContext) { _suppressionTargetInfo = suppressionTargetInfo; }
private PragmaRemoveAction( SuppressionTargetInfo suppressionTargetInfo, Document document, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool forFixMultipleContext = false) : base(diagnostic, fixer, forFixMultipleContext) { _document = document; _suppressionTargetInfo = suppressionTargetInfo; }
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)); }
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 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; }
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); } }
internal async static Task<Document> GetChangeDocumentWithPragmaAdjustedAsync( Document document, TextSpan diagnosticSpan, SuppressionTargetInfo suppressionTargetInfo, Func<SyntaxToken, TextSpan, Task<SyntaxToken>> getNewStartToken, Func<SyntaxToken, TextSpan, Task<SyntaxToken>> getNewEndToken, CancellationToken cancellationToken) { var startToken = suppressionTargetInfo.StartToken; var endToken = suppressionTargetInfo.EndToken; var nodeWithTokens = suppressionTargetInfo.NodeWithTokens; var root = await nodeWithTokens.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var startAndEndTokenAreTheSame = startToken == endToken; SyntaxToken newStartToken = await getNewStartToken(startToken, diagnosticSpan).ConfigureAwait(false); SyntaxToken newEndToken = endToken; if (startAndEndTokenAreTheSame) { var annotation = new SyntaxAnnotation(); newEndToken = root.ReplaceToken(startToken, newStartToken.WithAdditionalAnnotations(annotation)).GetAnnotatedTokens(annotation).Single(); var spanChange = newStartToken.LeadingTrivia.FullSpan.Length - startToken.LeadingTrivia.FullSpan.Length; diagnosticSpan = new TextSpan(diagnosticSpan.Start + spanChange, diagnosticSpan.Length); } newEndToken = await getNewEndToken(newEndToken, diagnosticSpan).ConfigureAwait(false); SyntaxNode newNode; if (startAndEndTokenAreTheSame) { newNode = nodeWithTokens.ReplaceToken(startToken, newEndToken); } else { newNode = nodeWithTokens.ReplaceTokens(new[] { startToken, endToken }, (o, n) => o == startToken ? newStartToken : newEndToken); } var newRoot = root.ReplaceNode(nodeWithTokens, newNode); return document.WithSyntaxRoot(newRoot); }
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; } }
private async Task <IEnumerable <CodeFix> > GetSuppressionsAsync(Document documentOpt, Project project, IEnumerable <Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, bool skipSuppressMessage, bool skipUnsuppress, CancellationToken cancellationToken) { // We only care about diagnostics that can be suppressed/unsuppressed. diagnostics = diagnostics.Where(CanBeSuppressedOrUnsuppressed); if (diagnostics.IsEmpty()) { return(SpecializedCollections.EmptyEnumerable <CodeFix>()); } if (!skipSuppressMessage) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var suppressMessageAttribute = compilation.SuppressMessageAttributeType(); skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute(); } var result = new List <CodeFix>(); foreach (var diagnostic in diagnostics) { if (!diagnostic.IsSuppressed) { var nestedActions = new List <NestedSuppressionCodeAction>(); if (diagnostic.Location.IsInSource && documentOpt != null) { // pragma warning disable. nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, diagnostic, this)); } // SuppressMessageAttribute suppression is not supported for compiler diagnostics. if (!skipSuppressMessage && !SuppressionHelpers.IsCompilerDiagnostic(diagnostic)) { // global assembly-level suppress message attribute. nestedActions.Add(new GlobalSuppressMessageCodeAction(suppressionTargetInfo.TargetSymbol, project, diagnostic, this)); } result.Add(new CodeFix(new SuppressionCodeAction(diagnostic, nestedActions), diagnostic)); } else if (!skipUnsuppress) { var codeAction = await RemoveSuppressionCodeAction.CreateAsync(suppressionTargetInfo, documentOpt, project, diagnostic, this, cancellationToken).ConfigureAwait(false); if (codeAction != null) { result.Add(new CodeFix(codeAction, diagnostic)); } } } return(result); }
private static void NormalizeTriviaOnTokens(AbstractSuppressionCodeFixProvider fixer, ref Document document, ref SuppressionTargetInfo suppressionTargetInfo) { var startToken = suppressionTargetInfo.StartToken; var endToken = suppressionTargetInfo.EndToken; var nodeWithTokens = suppressionTargetInfo.NodeWithTokens; var startAndEndTokensAreSame = startToken == endToken; var previousOfStart = startToken.GetPreviousToken(); var nextOfEnd = endToken.GetNextToken(); if (!previousOfStart.HasTrailingTrivia && !nextOfEnd.HasLeadingTrivia) { return; } var root = nodeWithTokens.SyntaxTree.GetRoot(); var subtreeRoot = root.FindNode(new TextSpan(previousOfStart.FullSpan.Start, nextOfEnd.FullSpan.End - 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 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); }
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); }
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 async Task<IEnumerable<CodeFix>> GetSuppressionsAsync(Document documentOpt, Project project, IEnumerable<Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, bool skipSuppressMessage, bool skipUnsuppress, CancellationToken cancellationToken) { // We only care about diagnostics that can be suppressed/unsuppressed. diagnostics = diagnostics.Where(CanBeSuppressedOrUnsuppressed); if (diagnostics.IsEmpty()) { return SpecializedCollections.EmptyEnumerable<CodeFix>(); } if (!skipSuppressMessage) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var suppressMessageAttribute = compilation.SuppressMessageAttributeType(); skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute(); } var result = new List<CodeFix>(); foreach (var diagnostic in diagnostics) { if (!diagnostic.IsSuppressed) { var nestedActions = new List<NestedSuppressionCodeAction>(); if (diagnostic.Location.IsInSource && documentOpt != null) { // pragma warning disable. nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, diagnostic, this)); } // SuppressMessageAttribute suppression is not supported for compiler diagnostics. if (!skipSuppressMessage && !SuppressionHelpers.IsCompilerDiagnostic(diagnostic)) { // global assembly-level suppress message attribute. nestedActions.Add(new GlobalSuppressMessageCodeAction(suppressionTargetInfo.TargetSymbol, project, diagnostic, this)); } result.Add(new CodeFix(new SuppressionCodeAction(diagnostic, nestedActions), diagnostic)); } else if (!skipUnsuppress) { var codeAction = await RemoveSuppressionCodeAction.CreateAsync(suppressionTargetInfo, documentOpt, project, diagnostic, this, cancellationToken).ConfigureAwait(false); if (codeAction != null) { result.Add(new CodeFix(codeAction, diagnostic)); } } } return result; }
private async Task <ImmutableArray <CodeFix> > GetSuppressionsAsync( Document documentOpt, Project project, IEnumerable <Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, 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 SyntaxFormattingOptions.FromDocumentAsync(documentOpt, 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)); // 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, cancellationToken).ConfigureAwait(false); if (codeAction != null) { result.Add(new CodeFix(project, codeAction, diagnostic)); } } } return(result.ToImmutableAndFree()); }
public async Task<IEnumerable<CodeFix>> GetSuppressionsAsync(Project project, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken) { if (!project.SupportsCompilation) { return SpecializedCollections.EmptyEnumerable<CodeFix>(); } var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var suppressionTargetInfo = new SuppressionTargetInfo() { TargetSymbol = compilation.Assembly }; return await GetSuppressionsAsync(documentOpt: null, project: project, diagnostics: diagnostics, suppressionTargetInfo: suppressionTargetInfo, skipSuppressMessage: false, skipUnsuppress: false, cancellationToken: cancellationToken).ConfigureAwait(false); }