EntitySystemAnalyzer.cs 11 KB

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