Программно Подавляем Предупреждения Анализатора Roslyn
Анализаторы Roslyn отлично подходят для обеспечения соблюдения стандартов кодирования и поиска ошибок. Однако иногда они могут ложно срабатывать или выдавать предупреждения, которые вы хотите игнорировать в определённых контекстах. Вы можете подавить эти предупреждения с помощью директив
#pragma или атрибутов [SuppressMessage], но оба подхода требуют изменения исходного кода.DiagnosticSuppressor — компонент Roslyn, который подавляет диагностические сообщения, сообщаемые другими анализаторами или компилятором. В отличие от обычного анализатора, он выдаёт новых диагностических сообщений, а проверяет существующие и решает, следует ли их подавить. Это особенно полезно, когда вам нужно контекстно-зависимое подавление без загромождения кода.
Для реализации DiagnosticSuppressor необходимо:
1. Создать класс, наследующий от DiagnosticSuppressor;
2. Декорировать класс с помощью
[DiagnosticAnalyzer(LanguageNames.CSharp)];3. Определить SuppressionDescriptor для каждого правила, которое вы хотите подавить;
4. Переопределить SupportedSuppressions, чтобы возвращать поддерживаемые дескрипторы;
5. Переопределить ReportSuppressions, чтобы реализовать логику подавления.
Пример
Допустим, вы используете Newtonsoft.Json для сериализации классов. Правило анализатора CA1507 предлагает заменить строковые литералы выражениями nameof. Однако, когда вы используете атрибут
[JsonProperty("propertyName")], анализатор помечает строковый литерал как нарушение CA1507. Но в этом сценарии вам может быть удобнее использовать строку, т.к. это имя свойства JSON является частью контракта API и должно оставаться неизменным, даже если вы переименуете свойство C#.Вот как можно реализовать подавитель для этого сценария:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
namespace Analyzer.Suppressors;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class CA1507Suppressor : DiagnosticSuppressor
{
// Определяем правило подавления
private static readonly
SuppressionDescriptor RuleJsonProperty = new(
id: "EXAMPLE0001", // ID «подавителя»
suppressedDiagnosticId: "CA1507", // ID правила
justification: "Suppress CA1507 on methods decorated with a [Newtonsoft.Json.JsonPropertyAttribute]."
);
// Регистрируем подавление
public override ImmutableArray<SuppressionDescriptor>
SupportedSuppressions => [RuleJsonProperty];
public override void ReportSuppressions(
SuppressionAnalysisContext ctx)
{
// Проверяем правила диагностики
foreach (var diag in ctx.ReportedDiagnostics)
{
// Получаем локацию диагностики и синтаксическое дерево
var location = diag.Location;
var tree = location?.SourceTree;
if (tree is null)
continue;
// Находим ноду в дереве
var root = tree.GetRoot(ctx.CancellationToken);
var node = root.FindNode(location!.SourceSpan);
if (node is null)
continue;
var parent = node.FirstAncestorOrSelf<AttributeSyntax>();
if (parent is null)
continue;
var semanticModel = ctx.GetSemanticModel(tree);
var info = semanticModel.GetSymbolInfo(parent, ctx.CancellationToken);
if (info.Symbol is not IMethodSymbol mtdSymb)
continue;
// Проверяем, что тип атрибута Newtonsoft.Json.JsonPropertyAttribute
var attrType = ctx.Compilation.GetTypeByMetadataName(
"Newtonsoft.Json.JsonPropertyAttribute");
if (attrType is null)
continue;
if (mtdSymb.ContainingType.Equals(attrType, SymbolEqualityComparer.Default))
{
// Подавляем
var suppr = Suppression.Create(RuleJsonProperty, diag);
ctx.ReportSuppression(suppr);
}
}
}
}
Источник: https://www.meziantou.net/suppressing-roslyn-analyzer-warnings-programmatically-using-diagnosticsuppressor.htm