提交 dc3733fd 编写于 作者: M Mihaly Marton

Resurrected the option to suppress in source using attributes (see...

Resurrected the option to suppress in source using attributes (see https://github.com/dotnet/roslyn/issues/17218)
The code was taken from the history (https://github.com/dotnet/roslyn/tree/4dfefe7b49c33d1d078494d52a84b16772158b11) and adapted to latest changes.
TODO:
* add unit tests
* title needs translation
上级 a8b93486
......@@ -87,23 +87,55 @@ protected override SyntaxNode AddGlobalSuppressMessageAttribute(SyntaxNode newRo
var leadingTriviaForAttributeList = isFirst && !compilationRoot.HasLeadingTrivia ?
SyntaxFactory.TriviaList(SyntaxFactory.Comment(GlobalSuppressionsFileHeaderComment)) :
default;
var attributeList = CreateAttributeList(targetSymbol, diagnostic, leadingTrivia: leadingTriviaForAttributeList, needsLeadingEndOfLine: !isFirst);
var attributeList = CreateAttributeList(targetSymbol, diagnostic, isAssemblyAttribute: true, leadingTrivia: leadingTriviaForAttributeList, needsLeadingEndOfLine: !isFirst);
attributeList = (AttributeListSyntax)Formatter.Format(attributeList, workspace, cancellationToken: cancellationToken);
return compilationRoot.AddAttributeLists(attributeList);
}
protected override SyntaxNode AddLocalSuppressMessageAttribute(SyntaxNode targetNode, ISymbol targetSymbol, Diagnostic diagnostic)
{
var memberNode = (MemberDeclarationSyntax)targetNode;
SyntaxTriviaList leadingTriviaForAttributeList;
bool needsLeadingEndOfLine;
if (!memberNode.GetAttributes().Any())
{
leadingTriviaForAttributeList = memberNode.GetLeadingTrivia();
memberNode = memberNode.WithoutLeadingTrivia();
needsLeadingEndOfLine = !leadingTriviaForAttributeList.Any() || !IsEndOfLine(leadingTriviaForAttributeList.Last());
}
else
{
leadingTriviaForAttributeList = default(SyntaxTriviaList);
needsLeadingEndOfLine = true;
}
var attributeList = CreateAttributeList(targetSymbol, diagnostic, isAssemblyAttribute: false, leadingTrivia: leadingTriviaForAttributeList, needsLeadingEndOfLine: needsLeadingEndOfLine);
return memberNode.AddAttributeLists(attributeList);
}
private AttributeListSyntax CreateAttributeList(
ISymbol targetSymbol,
Diagnostic diagnostic,
bool isAssemblyAttribute,
SyntaxTriviaList leadingTrivia,
bool needsLeadingEndOfLine)
{
var attributeArguments = CreateAttributeArguments(targetSymbol, diagnostic);
var attributeArguments = CreateAttributeArguments(targetSymbol, diagnostic, isAssemblyAttribute);
var attribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName(SuppressMessageAttributeName), attributeArguments);
var attributes = new SeparatedSyntaxList<AttributeSyntax>().Add(attribute);
var targetSpecifier = SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword));
var attributeList = SyntaxFactory.AttributeList(targetSpecifier, attributes);
AttributeListSyntax attributeList;
if (isAssemblyAttribute)
{
var targetSpecifier = SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword));
attributeList = SyntaxFactory.AttributeList(targetSpecifier, attributes);
}
else
{
attributeList = SyntaxFactory.AttributeList(attributes);
}
var endOfLineTrivia = SyntaxFactory.ElasticCarriageReturnLineFeed;
var triviaList = SyntaxFactory.TriviaList();
......@@ -115,7 +147,7 @@ protected override SyntaxNode AddGlobalSuppressMessageAttribute(SyntaxNode newRo
return attributeList.WithLeadingTrivia(leadingTrivia.AddRange(triviaList));
}
private AttributeArgumentListSyntax CreateAttributeArguments(ISymbol targetSymbol, Diagnostic diagnostic)
private AttributeArgumentListSyntax CreateAttributeArguments(ISymbol targetSymbol, Diagnostic diagnostic, bool isAssemblyAttribute)
{
// SuppressMessage("Rule Category", "Rule Id", Justification = nameof(Justification), Scope = nameof(Scope), Target = nameof(Target))
var category = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(diagnostic.Descriptor.Category));
......@@ -131,17 +163,20 @@ private AttributeArgumentListSyntax CreateAttributeArguments(ISymbol targetSymbo
var attributeArgumentList = SyntaxFactory.AttributeArgumentList().AddArguments(categoryArgument, ruleIdArgument, justificationArgument);
var scopeString = GetScopeString(targetSymbol.Kind);
if (scopeString != null)
if (isAssemblyAttribute)
{
var scopeExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(scopeString));
var scopeArgument = SyntaxFactory.AttributeArgument(SyntaxFactory.NameEquals("Scope"), nameColon: null, expression: scopeExpr);
var targetString = GetTargetString(targetSymbol);
var targetExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(targetString));
var targetArgument = SyntaxFactory.AttributeArgument(SyntaxFactory.NameEquals("Target"), nameColon: null, expression: targetExpr);
attributeArgumentList = attributeArgumentList.AddArguments(scopeArgument, targetArgument);
var scopeString = GetScopeString(targetSymbol.Kind);
if (scopeString != null)
{
var scopeExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(scopeString));
var scopeArgument = SyntaxFactory.AttributeArgument(SyntaxFactory.NameEquals("Scope"), nameColon: null, expression: scopeExpr);
var targetString = GetTargetString(targetSymbol);
var targetExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(targetString));
var targetArgument = SyntaxFactory.AttributeArgument(SyntaxFactory.NameEquals("Target"), nameColon: null, expression: targetExpr);
attributeArgumentList = attributeArgumentList.AddArguments(scopeArgument, targetArgument);
}
}
return attributeArgumentList;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
namespace Microsoft.CodeAnalysis.CodeFixes.Suppression
{
internal abstract partial class AbstractSuppressionCodeFixProvider : ISuppressionFixProvider
{
internal sealed class LocalSuppressMessageCodeAction : AbstractSuppressionCodeAction
{
private readonly AbstractSuppressionCodeFixProvider _fixer;
private readonly ISymbol _targetSymbol;
private readonly SyntaxNode _targetNode;
private readonly Document _document;
private readonly Diagnostic _diagnostic;
public LocalSuppressMessageCodeAction(AbstractSuppressionCodeFixProvider fixer, ISymbol targetSymbol, SyntaxNode targetNode, Document document, Diagnostic diagnostic)
: base(fixer, FeaturesResources.in_Source_attribute)
{
_fixer = fixer;
_targetSymbol = targetSymbol;
_targetNode = targetNode;
_document = document;
_diagnostic = diagnostic;
}
protected async override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
var newTargetNode = _fixer.AddLocalSuppressMessageAttribute(_targetNode, _targetSymbol, _diagnostic);
var root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newRoot = root.ReplaceNode(_targetNode, newTargetNode);
return _document.WithSyntaxRoot(newRoot);
}
protected override string DiagnosticIdForEquivalenceKey => _diagnostic.Id;
internal SyntaxNode TargetNode_TestOnly => _targetNode;
}
}
}
......@@ -45,6 +45,7 @@ public bool CanBeSuppressedOrUnsuppressed(Diagnostic diagnostic)
protected abstract SyntaxTriviaList CreatePragmaRestoreDirectiveTrivia(Diagnostic diagnostic, Func<SyntaxNode, SyntaxNode> formatNode, bool needsLeadingEndOfLine, bool needsTrailingEndOfLine);
protected abstract SyntaxNode AddGlobalSuppressMessageAttribute(SyntaxNode newRoot, ISymbol targetSymbol, Diagnostic diagnostic, Workspace workspace, CancellationToken cancellationToken);
protected abstract SyntaxNode AddLocalSuppressMessageAttribute(SyntaxNode targetNode, ISymbol targetSymbol, Diagnostic diagnostic);
protected abstract string DefaultFileExtension { get; }
protected abstract string SingleLineCommentStart { get; }
......@@ -152,6 +153,14 @@ internal async Task<ImmutableArray<PragmaWarningCodeAction>> GetPragmaSuppressio
{
// global assembly-level suppress message attribute.
nestedActions.Add(new GlobalSuppressMessageCodeAction(suppressionTargetInfo.TargetSymbol, project, diagnostic, this));
// local suppress message attribute
// please note that in order to avoid issues with exising 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, suppressionTargetInfo.TargetMemberNode, documentOpt, diagnostic));
}
}
if (nestedActions.Count > 0)
......@@ -180,6 +189,7 @@ internal class SuppressionTargetInfo
public SyntaxToken StartToken { get; set; }
public SyntaxToken EndToken { get; set; }
public SyntaxNode NodeWithTokens { get; set; }
public SyntaxNode TargetMemberNode { get; set; }
}
private async Task<SuppressionTargetInfo> GetSuppressionTargetInfoAsync(Document document, TextSpan span, CancellationToken cancellationToken)
......@@ -261,7 +271,7 @@ private async Task<SuppressionTargetInfo> GetSuppressionTargetInfoAsync(Document
targetSymbol = semanticModel.Compilation.Assembly;
}
return new SuppressionTargetInfo() { TargetSymbol = targetSymbol, NodeWithTokens = nodeWithTokens, StartToken = startToken, EndToken = endToken };
return new SuppressionTargetInfo() { TargetSymbol = targetSymbol, NodeWithTokens = nodeWithTokens, StartToken = startToken, EndToken = endToken, TargetMemberNode = targetMemberNode };
}
internal SyntaxNode GetNodeWithTokens(SyntaxToken startToken, SyntaxToken endToken, SyntaxNode root)
......
......@@ -1863,6 +1863,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to in Source (attribute).
/// </summary>
internal static string in_Source_attribute {
get {
return ResourceManager.GetString("in_Source_attribute", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to in Suppression File.
/// </summary>
......
......@@ -1617,4 +1617,7 @@ This version used in: {2}</value>
<data name="Target_type_matches" xml:space="preserve">
<value>Target type matches</value>
</data>
<data name="in_Source_attribute" xml:space="preserve">
<value>in Source (attribute)</value>
</data>
</root>
\ No newline at end of file
......@@ -497,6 +497,11 @@
<target state="translated">obecná přetížení</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">přetížení</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">generische Überladungen</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">Überladung</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">sobrecargas genéricas</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">sobrecarga</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">surcharges génériques</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">surcharge</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">overload generici</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">overload</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">ジェネリック オーバーロード</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">オーバーロード</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">제네릭 오버로드</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">오버로드</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">przeciążenia ogólne</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">przeciążenie</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">sobrecargas genéricas</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">sobrecarga</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">универсальные перегрузки</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">перегрузка</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">genel aşırı yüklemeler</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">aşırı yükleme</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">多个泛型重载</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">重载</target>
......
......@@ -497,6 +497,11 @@
<target state="translated">泛型多載</target>
<note />
</trans-unit>
<trans-unit id="in_Source_attribute">
<source>in Source (attribute)</source>
<target state="new">in Source (attribute)</target>
<note />
</trans-unit>
<trans-unit id="overload">
<source>overload</source>
<target state="translated">多載</target>
......
......@@ -122,7 +122,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Suppression
Protected Overrides Function AddGlobalSuppressMessageAttribute(newRoot As SyntaxNode, targetSymbol As ISymbol, diagnostic As Diagnostic, workspace As Workspace, cancellationToken As CancellationToken) As SyntaxNode
Dim compilationRoot = DirectCast(newRoot, CompilationUnitSyntax)
Dim isFirst = Not compilationRoot.Attributes.Any()
Dim attributeList = CreateAttributeList(targetSymbol, diagnostic)
Dim attributeList = CreateAttributeList(targetSymbol, diagnostic, isAssemblyAttribute:=True)
Dim attributeStatement = SyntaxFactory.AttributesStatement(New SyntaxList(Of AttributeListSyntax)().Add(attributeList))
If Not isFirst Then
......@@ -144,16 +144,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Suppression
Return compilationRoot.AddAttributes(attributeStatement).WithLeadingTrivia(leadingTrivia)
End Function
Private Function CreateAttributeList(targetSymbol As ISymbol, diagnostic As Diagnostic) As AttributeListSyntax
Dim attributeTarget = SyntaxFactory.AttributeTarget(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword))
Protected Overrides Function AddLocalSuppressMessageAttribute(targetNode As SyntaxNode, targetSymbol As ISymbol, diagnostic As Diagnostic) As SyntaxNode
Dim memberNode = DirectCast(targetNode, StatementSyntax)
Dim attributeList = CreateAttributeList(targetSymbol, diagnostic, isAssemblyAttribute:=False)
Dim leadingTrivia = memberNode.GetLeadingTrivia()
memberNode = memberNode.WithoutLeadingTrivia()
Return memberNode.AddAttributeLists(attributeList).WithLeadingTrivia(leadingTrivia)
End Function
Private Function CreateAttributeList(targetSymbol As ISymbol, diagnostic As Diagnostic, isAssemblyAttribute As Boolean) As AttributeListSyntax
Dim attributeTarget = If(isAssemblyAttribute, SyntaxFactory.AttributeTarget(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword)), Nothing)
Dim attributeName = SyntaxFactory.ParseName(SuppressMessageAttributeName)
Dim attributeArguments = CreateAttributeArguments(targetSymbol, diagnostic)
Dim attributeArguments = CreateAttributeArguments(targetSymbol, diagnostic, isAssemblyAttribute)
Dim attribute As AttributeSyntax = SyntaxFactory.Attribute(attributeTarget, attributeName, attributeArguments)
Return SyntaxFactory.AttributeList().AddAttributes(attribute)
End Function
Private Function CreateAttributeArguments(targetSymbol As ISymbol, diagnostic As Diagnostic) As ArgumentListSyntax
Private Function CreateAttributeArguments(targetSymbol As ISymbol, diagnostic As Diagnostic, isAssemblyAttribute As Boolean) As ArgumentListSyntax
' SuppressMessage("Rule Category", "Rule Id", Justification := "Justification", Scope := "Scope", Target := "Target")
Dim category = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(diagnostic.Descriptor.Category))
Dim categoryArgument = SyntaxFactory.SimpleArgument(category)
......@@ -169,15 +177,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.Suppression
Dim attributeArgumentList = SyntaxFactory.ArgumentList().AddArguments(categoryArgument, ruleIdArgument, justificationArgument)
Dim scopeString = GetScopeString(targetSymbol.Kind)
If scopeString IsNot Nothing Then
Dim scopeExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(scopeString))
Dim scopeArgument = SyntaxFactory.SimpleArgument(SyntaxFactory.NameColonEquals(SyntaxFactory.IdentifierName("Scope")), expression:=scopeExpr)
If isAssemblyAttribute Then
If scopeString IsNot Nothing Then
Dim scopeExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(scopeString))
Dim scopeArgument = SyntaxFactory.SimpleArgument(SyntaxFactory.NameColonEquals(SyntaxFactory.IdentifierName("Scope")), expression:=scopeExpr)
Dim targetString = GetTargetString(targetSymbol)
Dim targetExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(targetString))
Dim targetArgument = SyntaxFactory.SimpleArgument(SyntaxFactory.NameColonEquals(SyntaxFactory.IdentifierName("Target")), expression:=targetExpr)
Dim targetString = GetTargetString(targetSymbol)
Dim targetExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(targetString))
Dim targetArgument = SyntaxFactory.SimpleArgument(SyntaxFactory.NameColonEquals(SyntaxFactory.IdentifierName("Target")), expression:=targetExpr)
attributeArgumentList = attributeArgumentList.AddArguments(scopeArgument, targetArgument)
attributeArgumentList = attributeArgumentList.AddArguments(scopeArgument, targetArgument)
End If
End If
Return attributeArgumentList
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册