EntitySystemAnalyzer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.Collections.Immutable;
  3. using System.Linq;
  4. using System.Text;
  5. using Microsoft.CodeAnalysis;
  6. using Microsoft.CodeAnalysis.CSharp.Syntax;
  7. using Microsoft.CodeAnalysis.Diagnostics;
  8. namespace ET.Analyzer;
  9. [DiagnosticAnalyzer(LanguageNames.CSharp)]
  10. public class EntitySystemAnalyzer: DiagnosticAnalyzer
  11. {
  12. public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(EntitySystemAnalyzerRule.Rule,EntitySystemMethodNeedSystemOfAttrAnalyzerRule.Rule);
  13. public override void Initialize(AnalysisContext context)
  14. {
  15. if (!AnalyzerGlobalSetting.EnableAnalyzer)
  16. {
  17. return;
  18. }
  19. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
  20. context.EnableConcurrentExecution();
  21. context.RegisterSymbolAction(this.Analyzer, SymbolKind.NamedType);
  22. context.RegisterSymbolAction(this.AnalyzeIsSystemMethodValid,SymbolKind.NamedType);
  23. }
  24. private static ImmutableArray<ETSystemData> SupportedETSystemDatas => ImmutableArray.Create(
  25. new ETSystemData(Definition.EntitySystemOfAttribute, Definition.EntitySystemAttribute, Definition.EntityType,Definition.EntitySystemAttributeMetaName,
  26. new SystemMethodData(Definition.IAwakeInterface, Definition.AwakeMethod),
  27. new SystemMethodData(Definition.IUpdateInterface, Definition.UpdateMethod),
  28. new SystemMethodData(Definition.IDestroyInterface, Definition.DestroyMethod),
  29. new SystemMethodData(Definition.IAddComponentInterface, Definition.AddComponentMethod),
  30. new SystemMethodData(Definition.IDeserializeInterface, Definition.DeserializeMethod),
  31. new SystemMethodData(Definition.IGetComponentInterface, Definition.GetComponentMethod),
  32. new SystemMethodData(Definition.ILoadInterface, Definition.LoadMethod),
  33. new SystemMethodData(Definition.ILateUpdateInterface, Definition.LateUpdateMethod),
  34. new SystemMethodData(Definition.ISerializeInterface, Definition.SerializeMethod),
  35. new SystemMethodData(Definition.ILSRollbackInterface,Definition.LSRollbackMethod)),
  36. new ETSystemData(Definition.LSEntitySystemOfAttribute,Definition.LSEntitySystemAttribute,Definition.LSEntityType,Definition.LSEntitySystemAttributeMetaName,
  37. new SystemMethodData(Definition.IAwakeInterface, Definition.AwakeMethod),
  38. new SystemMethodData(Definition.ILSUpdateInterface, Definition.LSUpdateMethod),
  39. new SystemMethodData(Definition.IDestroyInterface, Definition.DestroyMethod),
  40. new SystemMethodData(Definition.IAddComponentInterface, Definition.AddComponentMethod),
  41. new SystemMethodData(Definition.IDeserializeInterface, Definition.DeserializeMethod),
  42. new SystemMethodData(Definition.IGetComponentInterface, Definition.GetComponentMethod),
  43. new SystemMethodData(Definition.ILoadInterface, Definition.LoadMethod),
  44. new SystemMethodData(Definition.ISerializeInterface, Definition.SerializeMethod),
  45. new SystemMethodData(Definition.ILSRollbackInterface,Definition.LSRollbackMethod)
  46. )
  47. );
  48. public class ETSystemData
  49. {
  50. public string EntityTypeName;
  51. public string SystemOfAttribute;
  52. public string SystemAttributeShowName;
  53. public string SystemAttributeMetaName;
  54. public SystemMethodData[] SystemMethods;
  55. public ETSystemData(string systemOfAttribute, string systemAttributeShowName, string entityTypeName, string systemAttributeMetaName, params SystemMethodData[] systemMethods)
  56. {
  57. this.SystemOfAttribute = systemOfAttribute;
  58. this.SystemAttributeShowName = systemAttributeShowName;
  59. this.EntityTypeName = entityTypeName;
  60. this.SystemAttributeMetaName = systemAttributeMetaName;
  61. this.SystemMethods = systemMethods;
  62. }
  63. }
  64. public struct SystemMethodData
  65. {
  66. public string InterfaceName;
  67. public string MethodName;
  68. public SystemMethodData(string interfaceName, string methodName)
  69. {
  70. this.InterfaceName = interfaceName;
  71. this.MethodName = methodName;
  72. }
  73. }
  74. private void Analyzer(SymbolAnalysisContext context)
  75. {
  76. if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
  77. {
  78. return;
  79. }
  80. ImmutableDictionary<string, string?>.Builder? builder = null;
  81. foreach (ETSystemData? supportedEtSystemData in SupportedETSystemDatas)
  82. {
  83. if (supportedEtSystemData != null)
  84. {
  85. this.AnalyzeETSystem(context, supportedEtSystemData, ref builder);
  86. }
  87. }
  88. this.ReportNeedGenerateSystem(context, namedTypeSymbol, ref builder);
  89. }
  90. private void AnalyzeETSystem(SymbolAnalysisContext context, ETSystemData etSystemData, ref ImmutableDictionary<string, string?>.Builder? builder)
  91. {
  92. if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
  93. {
  94. return;
  95. }
  96. // 筛选出含有SystemOf标签的类
  97. AttributeData? attr = namedTypeSymbol.GetFirstAttribute(etSystemData.SystemOfAttribute);
  98. if (attr == null)
  99. {
  100. return;
  101. }
  102. // 获取所属的实体类symbol
  103. if (attr.ConstructorArguments[0].Value is not INamedTypeSymbol entityTypeSymbol)
  104. {
  105. return;
  106. }
  107. bool ignoreAwake = false;
  108. if (attr.ConstructorArguments.Length>=2 && attr.ConstructorArguments[1].Value is bool ignore)
  109. {
  110. ignoreAwake = ignore;
  111. }
  112. // 排除非Entity子类
  113. if (entityTypeSymbol.BaseType?.ToString() != etSystemData.EntityTypeName)
  114. {
  115. return;
  116. }
  117. foreach (INamedTypeSymbol? interfacetypeSymbol in entityTypeSymbol.AllInterfaces)
  118. {
  119. if (ignoreAwake && interfacetypeSymbol.IsInterface(Definition.IAwakeInterface))
  120. {
  121. continue;
  122. }
  123. foreach (SystemMethodData systemMethodData in etSystemData.SystemMethods)
  124. {
  125. if (interfacetypeSymbol.IsInterface(systemMethodData.InterfaceName))
  126. {
  127. if (interfacetypeSymbol.IsGenericType)
  128. {
  129. var typeArgs = ImmutableArray.Create<ITypeSymbol>(entityTypeSymbol).AddRange(interfacetypeSymbol.TypeArguments);
  130. if (!namedTypeSymbol.HasMethodWithParams(systemMethodData.MethodName, typeArgs.ToArray()))
  131. {
  132. StringBuilder str = new();
  133. str.Append(entityTypeSymbol);
  134. str.Append("/");
  135. str.Append(etSystemData.SystemAttributeShowName);
  136. foreach (ITypeSymbol? typeArgument in interfacetypeSymbol.TypeArguments)
  137. {
  138. str.Append("/");
  139. str.Append(typeArgument);
  140. }
  141. AddProperty(ref builder, $"{systemMethodData.MethodName}`{interfacetypeSymbol.TypeArguments.Length}", str.ToString());
  142. }
  143. }
  144. else
  145. {
  146. if (!namedTypeSymbol.HasMethodWithParams(systemMethodData.MethodName, entityTypeSymbol))
  147. {
  148. AddProperty(ref builder, systemMethodData.MethodName, $"{entityTypeSymbol}/{etSystemData.SystemAttributeShowName}");
  149. }
  150. }
  151. break;
  152. }
  153. }
  154. }
  155. }
  156. private void AddProperty(ref ImmutableDictionary<string, string?>.Builder? builder, string methodMetaName, string methodArgs)
  157. {
  158. if (builder == null)
  159. {
  160. builder = ImmutableDictionary.CreateBuilder<string, string?>();
  161. }
  162. if (builder.TryGetValue(Definition.EntitySystemInterfaceSequence, out string? seqValue))
  163. {
  164. builder[Definition.EntitySystemInterfaceSequence] = $"{seqValue}/{methodMetaName}";
  165. }
  166. else
  167. {
  168. builder.Add(Definition.EntitySystemInterfaceSequence, methodMetaName);
  169. }
  170. builder.Add(methodMetaName, methodArgs);
  171. }
  172. private void ReportNeedGenerateSystem(SymbolAnalysisContext context, INamedTypeSymbol namedTypeSymbol, ref ImmutableDictionary<string, string?>.Builder? builder)
  173. {
  174. if (builder == null)
  175. {
  176. return;
  177. }
  178. foreach (SyntaxReference? reference in namedTypeSymbol.DeclaringSyntaxReferences)
  179. {
  180. if (reference.GetSyntax() is ClassDeclarationSyntax classDeclarationSyntax)
  181. {
  182. Diagnostic diagnostic = Diagnostic.Create(EntitySystemAnalyzerRule.Rule, classDeclarationSyntax.Identifier.GetLocation(),
  183. builder.ToImmutable(), namedTypeSymbol.Name);
  184. context.ReportDiagnostic(diagnostic);
  185. }
  186. }
  187. }
  188. private void AnalyzeIsSystemMethodValid(SymbolAnalysisContext context)
  189. {
  190. if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
  191. {
  192. return;
  193. }
  194. foreach (ISymbol? symbol in namedTypeSymbol.GetMembers())
  195. {
  196. if (symbol is not IMethodSymbol methodSymbol)
  197. {
  198. continue;
  199. }
  200. foreach (var etSystemData in SupportedETSystemDatas)
  201. {
  202. if (!methodSymbol.HasAttribute(etSystemData.SystemAttributeMetaName))
  203. {
  204. continue;
  205. }
  206. if (methodSymbol.Parameters.Length==0)
  207. {
  208. continue;
  209. }
  210. AttributeData? attr = namedTypeSymbol.GetFirstAttribute(etSystemData.SystemOfAttribute);
  211. if (attr == null || attr.ConstructorArguments[0].Value is not INamedTypeSymbol entityTypeSymbol
  212. || entityTypeSymbol.ToString()!=methodSymbol.Parameters[0].Type.ToString())
  213. {
  214. ReportNeedSystemOfAttr(context,methodSymbol,etSystemData);
  215. }
  216. }
  217. }
  218. }
  219. private void ReportNeedSystemOfAttr(SymbolAnalysisContext context, IMethodSymbol methodSymbol,ETSystemData etSystemData)
  220. {
  221. foreach (SyntaxReference? reference in methodSymbol.DeclaringSyntaxReferences)
  222. {
  223. if (reference.GetSyntax() is MethodDeclarationSyntax methodDeclarationSyntax)
  224. {
  225. Diagnostic diagnostic = Diagnostic.Create(EntitySystemMethodNeedSystemOfAttrAnalyzerRule.Rule, methodDeclarationSyntax.Identifier.GetLocation()
  226. ,methodSymbol.Name, etSystemData.SystemAttributeShowName,etSystemData.SystemOfAttribute);
  227. context.ReportDiagnostic(diagnostic);
  228. }
  229. }
  230. }
  231. }