内容目录
继承 DiagnosticAnalyzer 。
检测 async void
注册监听器:
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
// 注册分析类型,只分析方法
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
}
分析代码节点:
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var node = context.Node;
if (node.IsKind(SyntaxKind.MethodDeclaration))
{
var syntax = node as MethodDeclarationSyntax;
if (syntax is null) return;
AnalyzeMethodDeclarationSyntax(context, syntax);
}
}
判断节点是否为 async void 方法:
private void AnalyzeMethodDeclarationSyntax(SyntaxNodeAnalysisContext context, MethodDeclarationSyntax syntax)
{
var returnType = syntax.ReturnType as PredefinedTypeSyntax;
if (returnType == null) return;
if (returnType.Keyword.ValueText != SyntaxFactory.Token(SyntaxKind.VoidKeyword).ValueText) return;
if (syntax.Modifiers.Any(x => x.ValueText == "async"))
{
context.ReportDiagnostic(Diagnostic.Create(
descriptor: Rule,
location: returnType.GetLocation(),
messageArgs: "async void"));
}
}
如果开发者使用了 async void 代码,会提示报错。
检测使用异步方法未使用 await
注册监听器:
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ExpressionStatement);
}
分析节点:
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var node = context.Node;
var ex = node as ExpressionStatementSyntax;
if (ex is null) return;
var syntax = ex.Expression as InvocationExpressionSyntax;
if (syntax is null) return;
AnalyzeMethodDeclarationSyntax(context, syntax);
}
针对多种情况进行检测分析:
private static string[] BlockingCalls = new string[] { "GetAwaiter", "Result", "Wait" };
private void AnalyzeMethodDeclarationSyntax(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax syntax)
{
// 检查被调用的方法是否为 async Task 方法
var invokeMethod = context.SemanticModel.GetSymbolInfo(syntax).Symbol as IMethodSymbol;
if (invokeMethod == null || !ReturnTask(invokeMethod))
{
return;
}
// 获取被调用方法的名称
var methodSymbol = context
.SemanticModel
.GetSymbolInfo(syntax, context.CancellationToken)
.Symbol as IMethodSymbol;
// 查找此方法引用
var syntaxReference = methodSymbol
.DeclaringSyntaxReferences
.FirstOrDefault();
// 获取此方法在语法树中的定义
var methodDeclaration = syntaxReference.GetSyntax(context.CancellationToken) as MethodDeclarationSyntax;
if (methodDeclaration == null) return;
// 如果不是异步方法
if (!methodDeclaration.Modifiers.Any(x => x.ValueText == "async")) return;
// 已经使用了 await 等待
var isAwaited = syntax.Ancestors().OfType<AwaitExpressionSyntax>().Any();
if (isAwaited)
{
return;
}
//var isUnderLambda = FirstAncestorOrSelfUnderGivenNode<LambdaExpressionSyntax>(syntax, node) != null;
//if (isUnderLambda)
//{
// return;
//}
// 检查是否使用了 await、_ = xxx、BlockingCalls
bool isInvocationWaited = false;
foreach (var parent in syntax.Ancestors())
{
var assignment = parent as AssignmentExpressionSyntax;
// 已经使用了弃元 _ = xxx
if (assignment != null)
{
return;
}
var parentMemberAccess = parent as MemberAccessExpressionSyntax;
if (parentMemberAccess?.Name != null)
{
if (BlockingCalls.Any(a => a.Equals(parentMemberAccess.Name.Identifier.ValueText, StringComparison.OrdinalIgnoreCase)))
{
isInvocationWaited = true;
break;
}
}
if (isInvocationWaited)
{
return;
}
}
context.ReportDiagnostic(Diagnostic.Create(
descriptor: Rule,
location: syntax.GetLocation()));
}
public static T FirstAncestorOrSelfUnderGivenNode<T>(SyntaxNode node, SyntaxNode parent) where T : SyntaxNode
{
var current = node;
while (current != null && current != parent)
{
var temp = current as T;
if (temp != null)
{
return temp;
}
current = current.Parent;
}
return null;
}
public static bool IsTask(ITypeSymbol type)
{
return type.ContainingNamespace?.ToDisplayString() == "System.Threading.Tasks" &&
(type.Name == "Task" || type.Name == "ValueTask");
}
public static bool ReturnTask(IMethodSymbol symbol)
{
return !symbol.ReturnsVoid && IsTask(symbol.ReturnType);
}
文章评论