ETTaskAnalyzer.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. using System.Collections.Immutable;
  2. using System.Linq;
  3. using Microsoft.CodeAnalysis;
  4. using Microsoft.CodeAnalysis.CSharp;
  5. using Microsoft.CodeAnalysis.CSharp.Syntax;
  6. using Microsoft.CodeAnalysis.Diagnostics;
  7. namespace ET.Analyzer
  8. {
  9. [DiagnosticAnalyzer(LanguageNames.CSharp)]
  10. public class ETTaskAnalyzer:DiagnosticAnalyzer
  11. {
  12. public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
  13. ImmutableArray.Create(ETTaskInSyncMethodAnalyzerRule.Rule,ETTaskInAsyncMethodAnalyzerRule.Rule);
  14. public override void Initialize(AnalysisContext context)
  15. {
  16. if (!AnalyzerGlobalSetting.EnableAnalyzer)
  17. {
  18. return;
  19. }
  20. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
  21. context.EnableConcurrentExecution();
  22. context.RegisterSyntaxNodeAction(this.AnalyzeMemberAccessExpression,SyntaxKind.SimpleMemberAccessExpression);
  23. }
  24. private void AnalyzeMemberAccessExpression(SyntaxNodeAnalysisContext context)
  25. {
  26. if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllModelHotfix))
  27. {
  28. return;
  29. }
  30. if (!(context.Node is MemberAccessExpressionSyntax memberAccessExpressionSyntax))
  31. {
  32. return;
  33. }
  34. // 获取方法调用Syntax 对应的methodSymbol
  35. if (!(memberAccessExpressionSyntax?.Parent is InvocationExpressionSyntax invocationExpressionSyntax) ||
  36. !(context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol is IMethodSymbol methodSymbol))
  37. {
  38. return;
  39. }
  40. //忽略void返回值函数
  41. if (methodSymbol.ReturnsVoid)
  42. {
  43. return;
  44. }
  45. if (!(methodSymbol.ReturnType is INamedTypeSymbol namedTypeSymbol))
  46. {
  47. return;
  48. }
  49. // 筛选出返回值为ETTask 和ETTask<T>的函数
  50. if (namedTypeSymbol.Name!=Definition.ETTask)
  51. {
  52. return;
  53. }
  54. // 获取ETTask函数调用处所在的函数体
  55. var containingMethodDeclarationSyntax = memberAccessExpressionSyntax?.GetNeareastAncestor<MethodDeclarationSyntax>();
  56. if (containingMethodDeclarationSyntax==null)
  57. {
  58. return;
  59. }
  60. IMethodSymbol? containingMethodSymbol = context.SemanticModel.GetDeclaredSymbol(containingMethodDeclarationSyntax);
  61. if (containingMethodSymbol==null)
  62. {
  63. return;
  64. }
  65. // ETTask函数在 ()=>Function(); 形式的lanmda表达式中时
  66. if (invocationExpressionSyntax.Parent is ParenthesizedLambdaExpressionSyntax)
  67. {
  68. Diagnostic diagnostic = Diagnostic.Create(ETTaskInSyncMethodAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
  69. memberAccessExpressionSyntax?.Name);
  70. context.ReportDiagnostic(diagnostic);
  71. return;
  72. }
  73. // 方法体内ETTask单独调用时
  74. if (invocationExpressionSyntax.Parent is ExpressionStatementSyntax)
  75. {
  76. if (containingMethodSymbol.IsAsync)
  77. {
  78. Diagnostic diagnostic = Diagnostic.Create(ETTaskInAsyncMethodAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
  79. memberAccessExpressionSyntax?.Name);
  80. context.ReportDiagnostic(diagnostic);
  81. }
  82. else
  83. {
  84. Diagnostic diagnostic = Diagnostic.Create(ETTaskInSyncMethodAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
  85. memberAccessExpressionSyntax?.Name);
  86. context.ReportDiagnostic(diagnostic);
  87. }
  88. }
  89. }
  90. }
  91. }