AnalyzerHelper.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.CodeAnalysis;
  5. using Microsoft.CodeAnalysis.CSharp;
  6. using Microsoft.CodeAnalysis.CSharp.Syntax;
  7. using Microsoft.CodeAnalysis.Diagnostics;
  8. using Microsoft.CodeAnalysis.FlowAnalysis;
  9. using Exception = System.Exception;
  10. namespace ET.Analyzer
  11. {
  12. public static class AnalyzerHelper
  13. {
  14. /// <summary>
  15. /// 获取语法树节点的子节点中第一个指定类型节点
  16. /// </summary>
  17. /// <param name="syntaxNode">语法树节点</param>
  18. /// <typeparam name="T">指定语法节点类型</typeparam>
  19. /// <returns>第一个指定类型节点</returns>
  20. public static T? GetFirstChild<T>(this SyntaxNode syntaxNode) where T : SyntaxNode
  21. {
  22. foreach (SyntaxNode? childNode in syntaxNode.ChildNodes())
  23. {
  24. if (childNode.GetType() == typeof (T))
  25. {
  26. return childNode as T;
  27. }
  28. }
  29. return null;
  30. }
  31. public static SyntaxNode? GetFirstChild(this SyntaxNode syntaxNode)
  32. {
  33. var childNodes = syntaxNode.ChildNodes();
  34. if (childNodes.Count() > 0)
  35. {
  36. return childNodes.First();
  37. }
  38. return null;
  39. }
  40. /// <summary>
  41. /// 获取语法树节点的子节点中最后一个指定类型节点
  42. /// </summary>
  43. /// <param name="syntaxNode">语法树节点</param>
  44. /// <typeparam name="T">指定语法节点类型</typeparam>
  45. /// <returns>最后一个指定类型节点</returns>
  46. public static T? GetLastChild<T>(this SyntaxNode syntaxNode) where T : SyntaxNode
  47. {
  48. foreach (SyntaxNode? childNode in syntaxNode.ChildNodes().Reverse())
  49. {
  50. if (childNode.GetType() == typeof (T))
  51. {
  52. return childNode as T;
  53. }
  54. }
  55. return null;
  56. }
  57. /// <summary>
  58. /// 获取语法节点所属的ClassDeclarationSyntax
  59. /// </summary>
  60. public static ClassDeclarationSyntax? GetParentClassDeclaration(this SyntaxNode syntaxNode)
  61. {
  62. SyntaxNode? parentNode = syntaxNode.Parent;
  63. while (parentNode != null)
  64. {
  65. if (parentNode is ClassDeclarationSyntax classDeclarationSyntax)
  66. {
  67. return classDeclarationSyntax;
  68. }
  69. parentNode = parentNode.Parent;
  70. }
  71. return null;
  72. }
  73. /// <summary>
  74. /// INamedTypeSymbol 是否有指定的Attribute
  75. /// </summary>
  76. public static bool HasAttribute(this INamedTypeSymbol namedTypeSymbol, string AttributeName)
  77. {
  78. foreach (AttributeData? attributeData in namedTypeSymbol.GetAttributes())
  79. {
  80. if (attributeData.AttributeClass?.ToString() == AttributeName)
  81. {
  82. return true;
  83. }
  84. }
  85. return false;
  86. }
  87. /// <summary>
  88. /// INamedTypeSymbol 是否有指定的基类Attribute
  89. /// </summary>
  90. public static bool HasBaseAttribute(this INamedTypeSymbol namedTypeSymbol, string AttributeName)
  91. {
  92. foreach (AttributeData? attributeData in namedTypeSymbol.GetAttributes())
  93. {
  94. INamedTypeSymbol? attributeType = attributeData.AttributeClass?.BaseType;
  95. while (attributeType != null)
  96. {
  97. if (attributeType.ToString() == AttributeName)
  98. {
  99. return true;
  100. }
  101. attributeType = attributeType.BaseType;
  102. }
  103. }
  104. return false;
  105. }
  106. /// <summary>
  107. /// INamedTypeSymbol 获取指定类型的第一个Attribute
  108. /// </summary>
  109. public static AttributeData? GetFirstAttribute(this INamedTypeSymbol namedTypeSymbol, string AttributeName)
  110. {
  111. foreach (AttributeData? attributeData in namedTypeSymbol.GetAttributes())
  112. {
  113. if (attributeData.AttributeClass?.ToString() == AttributeName)
  114. {
  115. return attributeData;
  116. }
  117. }
  118. return null;
  119. }
  120. /// <summary>
  121. /// INamedTypeSymbol 是否含有指定接口
  122. /// </summary>
  123. public static bool HasInterface(this INamedTypeSymbol namedTypeSymbol, string InterfaceName)
  124. {
  125. foreach (INamedTypeSymbol? iInterface in namedTypeSymbol.AllInterfaces)
  126. {
  127. if (iInterface.IsInterface(InterfaceName))
  128. {
  129. return true;
  130. }
  131. }
  132. return false;
  133. }
  134. /// <summary>
  135. /// 某个接口symbol 是否是指定的接口
  136. /// </summary>
  137. public static bool IsInterface(this INamedTypeSymbol namedTypeSymbol, string InterfaceName)
  138. {
  139. return $"{namedTypeSymbol.GetNameSpace()}.{namedTypeSymbol.Name}" == InterfaceName;
  140. }
  141. /// <summary>
  142. /// 判断指定的程序集是否需要分析
  143. /// </summary>
  144. public static bool IsAssemblyNeedAnalyze(string? assemblyName, params string[] analyzeAssemblyNames)
  145. {
  146. if (assemblyName == null)
  147. {
  148. return false;
  149. }
  150. foreach (string analyzeAssemblyName in analyzeAssemblyNames)
  151. {
  152. if (assemblyName == analyzeAssemblyName)
  153. {
  154. return true;
  155. }
  156. }
  157. return false;
  158. }
  159. /// <summary>
  160. /// 获取 成员访问语法节点的父级类型
  161. /// </summary>
  162. public static ITypeSymbol? GetMemberAccessSyntaxParentType(this MemberAccessExpressionSyntax memberAccessExpressionSyntax,
  163. SemanticModel semanticModel)
  164. {
  165. SyntaxNode? firstChildSyntaxNode = memberAccessExpressionSyntax.GetFirstChild();
  166. if (firstChildSyntaxNode == null)
  167. {
  168. return null;
  169. }
  170. ISymbol? firstChildSymbol = semanticModel.GetSymbolInfo(firstChildSyntaxNode).Symbol;
  171. if (firstChildSymbol == null)
  172. {
  173. return null;
  174. }
  175. if (firstChildSymbol is ILocalSymbol localSymbol)
  176. {
  177. return localSymbol.Type;
  178. }
  179. if (firstChildSymbol is IParameterSymbol parameterSymbol)
  180. {
  181. return parameterSymbol.Type;
  182. }
  183. if (firstChildSymbol is IPropertySymbol propertySymbol)
  184. {
  185. return propertySymbol.Type;
  186. }
  187. if (firstChildSymbol is IMethodSymbol methodSymbol)
  188. {
  189. return methodSymbol.ReturnType;
  190. }
  191. if (firstChildSymbol is IFieldSymbol fieldSymbol)
  192. {
  193. return fieldSymbol.Type;
  194. }
  195. if (firstChildSymbol is IEventSymbol eventSymbol)
  196. {
  197. return eventSymbol.Type;
  198. }
  199. return null;
  200. }
  201. /// <summary>
  202. /// 获取最近的指定类型祖先节点
  203. /// </summary>
  204. public static T? GetNeareastAncestor<T>(this SyntaxNode syntaxNode) where T:SyntaxNode
  205. {
  206. foreach (var ancestorNode in syntaxNode.Ancestors())
  207. {
  208. if (ancestorNode is T Tancestor)
  209. {
  210. return Tancestor;
  211. }
  212. }
  213. return null ;
  214. }
  215. /// <summary>
  216. /// 判断函数是否是否含有指定类型的参数
  217. /// </summary>
  218. public static bool HasParameterType(this IMethodSymbol methodSymbol, string parameterType, out IParameterSymbol? cencelTokenSymbol)
  219. {
  220. foreach (var parameterSymbol in methodSymbol.Parameters)
  221. {
  222. if (parameterSymbol.Type.ToString() == parameterType)
  223. {
  224. cencelTokenSymbol = parameterSymbol;
  225. return true;
  226. }
  227. }
  228. cencelTokenSymbol = null;
  229. return false;
  230. }
  231. /// <summary>
  232. /// 获取所有指定类型的子节点
  233. /// </summary>
  234. public static IEnumerable<T> DescendantNodes<T>(this SyntaxNode syntaxNode) where T : SyntaxNode
  235. {
  236. foreach (var descendantNode in syntaxNode.DescendantNodes())
  237. {
  238. if (descendantNode is T node)
  239. {
  240. yield return node;
  241. }
  242. }
  243. }
  244. /// <summary>
  245. /// 获取与该语法节点同层级的上一个节点
  246. /// </summary>
  247. public static SyntaxNode? PreviousNode(this SyntaxNode syntaxNode)
  248. {
  249. if (syntaxNode.Parent==null)
  250. {
  251. return null;
  252. }
  253. int index = 0;
  254. foreach (var childNode in syntaxNode.Parent.ChildNodes())
  255. {
  256. if (childNode == syntaxNode)
  257. {
  258. break;
  259. }
  260. index++;
  261. }
  262. if (index==0)
  263. {
  264. return null;
  265. }
  266. return syntaxNode.Parent.ChildNodes().ElementAt(index-1);
  267. }
  268. /// <summary>
  269. /// 获取与该语法节点同层级的下一个节点
  270. /// </summary>
  271. public static SyntaxNode? NextNode(this SyntaxNode syntaxNode)
  272. {
  273. if (syntaxNode.Parent==null)
  274. {
  275. return null;
  276. }
  277. int index = 0;
  278. foreach (var childNode in syntaxNode.Parent.ChildNodes())
  279. {
  280. if (childNode == syntaxNode)
  281. {
  282. break;
  283. }
  284. index++;
  285. }
  286. if (index == syntaxNode.Parent.ChildNodes().Count()-1)
  287. {
  288. return null;
  289. }
  290. return syntaxNode.Parent.ChildNodes().ElementAt(index+1);
  291. }
  292. /// <summary>
  293. /// 获取await表达式所在的控制流block
  294. /// </summary>
  295. public static BasicBlock? GetAwaitStatementControlFlowBlock(StatementSyntax statementSyntax,AwaitExpressionSyntax awaitExpressionSyntax ,SemanticModel semanticModel)
  296. {
  297. // 跳过 return 表达式
  298. if (statementSyntax.IsKind(SyntaxKind.ReturnStatement))
  299. {
  300. return null;
  301. }
  302. var methodSyntax = statementSyntax.GetNeareastAncestor<MethodDeclarationSyntax>();
  303. if (methodSyntax==null)
  304. {
  305. return null;
  306. }
  307. // 构建表达式所在函数的控制流图
  308. var controlFlowGraph = ControlFlowGraph.Create(methodSyntax, semanticModel);
  309. if (controlFlowGraph==null)
  310. {
  311. return null;
  312. }
  313. if (statementSyntax is LocalDeclarationStatementSyntax)
  314. {
  315. return null;
  316. }
  317. BasicBlock? block = controlFlowGraph.Blocks.FirstOrDefault(x => x.Operations.Any(y => y.Syntax.Contains(statementSyntax)));
  318. return block;
  319. }
  320. /// <summary>
  321. /// 判断类是否为partial类
  322. /// </summary>
  323. public static bool IsPartial(this ClassDeclarationSyntax classDeclaration)
  324. {
  325. foreach (var modifier in classDeclaration.Modifiers)
  326. {
  327. if (modifier.IsKind(SyntaxKind.PartialKeyword))
  328. {
  329. return true;
  330. }
  331. }
  332. return false;
  333. }
  334. public static string? GetNameSpace(this INamedTypeSymbol namedTypeSymbol)
  335. {
  336. INamespaceSymbol? namespaceSymbol = namedTypeSymbol.ContainingNamespace;
  337. string? namespaceName = namespaceSymbol?.Name;
  338. while (namespaceSymbol?.ContainingNamespace != null)
  339. {
  340. namespaceSymbol = namespaceSymbol.ContainingNamespace;
  341. if (string.IsNullOrEmpty(namespaceSymbol.Name))
  342. {
  343. break;
  344. }
  345. namespaceName = $"{namespaceSymbol.Name}.{namespaceName}";
  346. }
  347. if (string.IsNullOrEmpty(namespaceName))
  348. {
  349. return null;
  350. }
  351. return namespaceName;
  352. }
  353. /// <summary>
  354. /// 根据语义模型的文件路径 判断是否需要分析
  355. /// </summary>
  356. public static bool IsSemanticModelNeedAnalyze(SemanticModel semanticModel, params string[] filePaths)
  357. {
  358. foreach (var filePath in filePaths)
  359. {
  360. if (semanticModel.SyntaxTree.FilePath.Contains(filePath))
  361. {
  362. return true;
  363. }
  364. }
  365. return false;
  366. }
  367. /// <summary>
  368. /// 类型symbol是否有指定名字 指定参数的方法
  369. /// </summary>
  370. public static bool HasMethodWithParams(this INamedTypeSymbol namedTypeSymbol, string methodName, params ITypeSymbol[] typeSymbols)
  371. {
  372. foreach (var member in namedTypeSymbol.GetMembers())
  373. {
  374. if (member is not IMethodSymbol methodSymbol)
  375. {
  376. continue;
  377. }
  378. if (methodSymbol.Name!=methodName)
  379. {
  380. continue;
  381. }
  382. if (typeSymbols.Length!=methodSymbol.Parameters.Length)
  383. {
  384. continue;
  385. }
  386. if (typeSymbols.Length==0)
  387. {
  388. return true;
  389. }
  390. bool isEqual = true;
  391. for (int i = 0; i < typeSymbols.Length; i++)
  392. {
  393. if (typeSymbols[i].ToString()!=methodSymbol.Parameters[i].Type.ToString())
  394. {
  395. isEqual = false;
  396. break;
  397. }
  398. }
  399. if (isEqual)
  400. {
  401. return true;
  402. }
  403. }
  404. return false;
  405. }
  406. /// <summary>
  407. /// 类型symbol是否有指定名字 指定参数的方法
  408. /// </summary>
  409. public static bool HasMethodWithParams(this INamedTypeSymbol namedTypeSymbol, string methodName, params string[] typeSymbols)
  410. {
  411. foreach (var member in namedTypeSymbol.GetMembers())
  412. {
  413. if (member is not IMethodSymbol methodSymbol)
  414. {
  415. continue;
  416. }
  417. if (methodSymbol.Name!=methodName)
  418. {
  419. continue;
  420. }
  421. if (typeSymbols.Length!=methodSymbol.Parameters.Length)
  422. {
  423. continue;
  424. }
  425. if (typeSymbols.Length==0)
  426. {
  427. return true;
  428. }
  429. bool isEqual = true;
  430. for (int i = 0; i < typeSymbols.Length; i++)
  431. {
  432. if (typeSymbols[i]!=methodSymbol.Parameters[i].Type.ToString())
  433. {
  434. isEqual = false;
  435. break;
  436. }
  437. }
  438. if (isEqual)
  439. {
  440. return true;
  441. }
  442. }
  443. return false;
  444. }
  445. /// <summary>
  446. /// 方法symbol 是否有指定的attribute
  447. /// </summary>
  448. public static bool HasAttribute(this IMethodSymbol methodSymbol, string AttributeName)
  449. {
  450. foreach (AttributeData? attributeData in methodSymbol.GetAttributes())
  451. {
  452. if (attributeData?.AttributeClass?.ToString()==AttributeName)
  453. {
  454. return true;
  455. }
  456. }
  457. return false;
  458. }
  459. }
  460. }