소스 검색

添加EntityDelegateDeclarationAnalyzer UniqueIdAnalyzer 新增UniqueId标签 (#368)

1.EntityDelegateDeclarationAnalyzer
禁止在实体类中声明委托字段和属性成员的约束
2.UniqueIdAnalyzer
新增UniqueIdAttribute, 被该标签标记的类会约束成员的const int 字段在类内部唯一 且在指定的数值区间内
susices 3 년 전
부모
커밋
1efcd5a323

+ 91 - 0
Share/Analyzer/Analyzer/EntityDelegateDeclarationAnalyzer.cs

@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace ET.Analyzer
+{
+    [DiagnosticAnalyzer(LanguageNames.CSharp)]
+    public class EntityDelegateDeclarationAnalyzer: DiagnosticAnalyzer
+    {
+        private const string Title = "实体类禁止声明委托字段或属性";
+
+        private const string MessageFormat = "实体类: {0} 不能在类内部声明委托字段或属性: {1}";
+
+        private const string Description = "实体类禁止声明委托字段或属性.";
+        
+        private const string EntityType = "ET.Entity";
+        
+        private static readonly DiagnosticDescriptor Rule =
+                new DiagnosticDescriptor(DiagnosticIds.DelegateAnalyzerRuleId,
+                    Title,
+                    MessageFormat,
+                    DiagnosticCategories.Model,
+                    DiagnosticSeverity.Error,
+                    true,
+                    Description);
+
+        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>ImmutableArray.Create(Rule);
+        
+        public override void Initialize(AnalysisContext context)
+        {
+            if (!AnalyzerGlobalSetting.EnableAnalyzer)
+            {
+                return;
+            }
+            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+            context.EnableConcurrentExecution();
+            //context.RegisterSymbolAction(this.Analyzer, SymbolKind.NamedType);
+        }
+
+        private void Analyzer(SymbolAnalysisContext context)
+        {
+            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllModel))
+            {
+                return;
+            }
+            
+            if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
+            {
+                return;
+            }
+
+            // 筛选出实体类
+            if (namedTypeSymbol.BaseType?.ToString() != EntityType)
+            {
+                return;
+            }
+
+            foreach (var member in namedTypeSymbol.GetMembers())
+            {
+                
+                if (member is IFieldSymbol fieldSymbol && fieldSymbol.Type.BaseType?.ToString()==typeof(MulticastDelegate).FullName)
+                {
+
+                    ReportDiagnostic(fieldSymbol,fieldSymbol.Name);
+                    continue;
+                }
+                
+                if (member is IPropertySymbol propertySymbol && propertySymbol.Type.BaseType?.ToString()==typeof(MulticastDelegate).FullName)
+                {
+
+                    ReportDiagnostic(propertySymbol,propertySymbol.Name);
+                    continue;
+                }
+            }
+            
+
+            void ReportDiagnostic(ISymbol symbol,string delegateName)
+            {
+                foreach (var syntaxReference in symbol.DeclaringSyntaxReferences)
+                {
+                    var syntax = syntaxReference.GetSyntax();
+                    Diagnostic diagnostic = Diagnostic.Create(Rule, syntax.GetLocation(),namedTypeSymbol.Name,delegateName);
+                    context.ReportDiagnostic(diagnostic);
+                }
+            }
+        }
+    }
+}
+

+ 98 - 0
Share/Analyzer/Analyzer/UniqueIdAnalyzer.cs

@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace ET.Analyzer
+{
+    [DiagnosticAnalyzer(LanguageNames.CSharp)]
+    public class UniqueIdAnalyzer : DiagnosticAnalyzer
+    {
+
+
+        private const string UniqueIdAttribute = "ET.UniqueIdAttribute";
+        
+
+
+        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>ImmutableArray.Create(UniqueIdRangeAnaluzerRule.Rule,UniqueIdDuplicateAnalyzerRule.Rule);
+        
+        
+        public override void Initialize(AnalysisContext context)
+        {
+            if (!AnalyzerGlobalSetting.EnableAnalyzer)
+            {
+                return;
+            }
+            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+            context.EnableConcurrentExecution();
+            context.RegisterSymbolAction(this.Analyzer, SymbolKind.NamedType);
+        }
+        
+        private void Analyzer(SymbolAnalysisContext context)
+        {
+            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllModel))
+            {
+                return;
+            }
+            
+            if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
+            {
+                return;
+            }
+
+            // 筛选出含有UniqueId标签的类
+            var attr = namedTypeSymbol.GetFirstAttribute(UniqueIdAttribute);
+            if (attr==null)
+            {
+                return;
+            }
+
+            // 获取id 最小值最大值
+            var minIdValue = attr.ConstructorArguments[0].Value;
+
+            var maxIdValue = attr.ConstructorArguments[1].Value;
+
+            if (minIdValue==null || maxIdValue==null)
+            {
+                return;
+            }
+
+            int minId = (int)minIdValue;
+
+            int maxId = (int)maxIdValue;
+
+            HashSet<int> IdSet = new HashSet<int>();
+
+            foreach (var member in namedTypeSymbol.GetMembers())
+            {
+                if (member is IFieldSymbol { IsConst: true, ConstantValue: int id } fieldSymbol)
+                {
+                    if (id<minId || id>maxId)
+                    {
+                        ReportDiagnostic(fieldSymbol,id, UniqueIdRangeAnaluzerRule.Rule);
+                    }else if (IdSet.Contains(id))
+                    {
+                        ReportDiagnostic(fieldSymbol,id,UniqueIdDuplicateAnalyzerRule.Rule);
+                    }
+                    else
+                    {
+                        IdSet.Add(id);
+                    }
+                }
+            }
+            
+            
+            void ReportDiagnostic(IFieldSymbol fieldSymbol, int idValue, DiagnosticDescriptor rule)
+            {
+                foreach (var syntaxReference in fieldSymbol.DeclaringSyntaxReferences)
+                {
+                    var syntax = syntaxReference.GetSyntax();
+                    Diagnostic diagnostic = Diagnostic.Create(rule, syntax.GetLocation(),namedTypeSymbol.Name,fieldSymbol.Name,idValue.ToString());
+                    context.ReportDiagnostic(diagnostic);
+                }
+            }
+        }
+    }
+}
+

+ 7 - 0
Share/Analyzer/Config/DiagnosticIds.cs

@@ -19,5 +19,12 @@
         public const string ETTaskInSyncMethodAnalyzerRuleId = "ET0008";
         
         public const string ETTaskInAsyncMethodAnalyzerRuleId = "ET0009";
+
+        public const string DelegateAnalyzerRuleId = "ET0010";
+
+        public const string UniqueIdRangeAnalyzerRuleId = "ET0011";
+        
+        public const string UniqueIdDuplicateAnalyzerRuleId = "ET0012";
+        
     }
 }

+ 36 - 0
Share/Analyzer/Config/DiagnosticRules.cs

@@ -37,4 +37,40 @@ namespace ET.Analyzer
                     true,
                     Description);
     }
+
+    public static class UniqueIdRangeAnaluzerRule
+    {
+        private const string Title = "唯一Id字段数值区间约束";
+
+        private const string MessageFormat = "类: {0} Id字段: {1}的值: {2} 不在约束的区间内, 请修改";
+
+        private const string Description = "唯一Id字段数值区间约束.";
+        
+        public static readonly DiagnosticDescriptor Rule =
+                new DiagnosticDescriptor(DiagnosticIds.UniqueIdRangeAnalyzerRuleId,
+                    Title,
+                    MessageFormat,
+                    DiagnosticCategories.Model,
+                    DiagnosticSeverity.Error,
+                    true,
+                    Description);
+    }
+
+    public static class UniqueIdDuplicateAnalyzerRule
+    {
+        private const string Title = "唯一Id字段禁止重复";
+
+        private const string MessageFormat = "类: {0} Id字段: {1}的值: {2} 与其他Id字段值重复, 请修改";
+
+        private const string Description = "唯一Id字段禁止重复.";
+        
+        public static readonly DiagnosticDescriptor Rule =
+                new DiagnosticDescriptor(DiagnosticIds.UniqueIdDuplicateAnalyzerRuleId,
+                    Title,
+                    MessageFormat,
+                    DiagnosticCategories.Model,
+                    DiagnosticSeverity.Error,
+                    true,
+                    Description);
+    }
 }

+ 24 - 0
Unity/Assets/Core/Object/UniqueIdAttribute.cs

@@ -0,0 +1,24 @@
+using System;
+
+namespace ET
+{
+    /// <summary>
+    /// 唯一Id标签
+    /// 使用此标签标记的类 会检测类内部的 const int 字段成员是否唯一
+    /// 可以指定唯一Id的最小值 最大值区间
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+    public class UniqueIdAttribute : Attribute
+    {
+        public int Min;
+
+        public int Max;
+        
+        public UniqueIdAttribute(int min = int.MinValue, int max = int.MaxValue)
+        {
+            this.Min = min;
+            this.Max = max;
+        }
+    }
+}
+

+ 11 - 0
Unity/Assets/Core/Object/UniqueIdAttribute.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ac9885deeb4fd7640a708df80bdf8920
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1 - 0
Unity/Codes/Model/Share/CallbackType.cs

@@ -1,5 +1,6 @@
 namespace ET
 {
+    [UniqueId(1,10000)]
     public static class CallbackType
     {
         public const int SessionStreamDispatcherClientOuter = 1;