| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- using System.Collections.Immutable;
- using System.Linq;
- using Microsoft.CodeAnalysis;
- using Microsoft.CodeAnalysis.CSharp;
- using Microsoft.CodeAnalysis.CSharp.Syntax;
- using Microsoft.CodeAnalysis.Diagnostics;
- namespace ET.Analyzer
- {
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- public class EntityFiledAccessAnalyzer: DiagnosticAnalyzer
- {
- private const string Title = "实体字段访问错误";
- private const string MessageFormat = "实体: {0} 字段: {1} 只能在实体类生命周期组件或友元类(含有FriendOfAttribute)中访问";
- private const string Description = "请使用实体类属性或方法访问其他实体字段.";
- private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticIds.EntityFiledAccessAnalyzerRuleId,
- Title,
- MessageFormat,
- DiagnosticCategories.Hotfix,
- 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.RegisterCompilationStartAction((analysisContext =>
- {
- if (AnalyzerHelper.IsAssemblyNeedAnalyze(analysisContext.Compilation.AssemblyName, AnalyzeAssembly.AllModelHotfix))
- {
- analysisContext.RegisterSemanticModelAction((this.AnalyzeSemanticModel));
- }
- } ));
- }
-
- private void AnalyzeSemanticModel(SemanticModelAnalysisContext analysisContext)
- {
- foreach (var memberAccessExpressionSyntax in analysisContext.SemanticModel.SyntaxTree.GetRoot().DescendantNodes<MemberAccessExpressionSyntax>())
- {
- AnalyzeMemberAccessExpression(analysisContext, memberAccessExpressionSyntax);
- }
- }
- private void AnalyzeMemberAccessExpression(SemanticModelAnalysisContext context, MemberAccessExpressionSyntax memberAccessExpressionSyntax)
- {
- // -----筛选出实体类的字段symbol-----
- ISymbol? filedSymbol = context.SemanticModel.GetSymbolInfo(memberAccessExpressionSyntax).Symbol;
- if (filedSymbol == null || !(filedSymbol is IFieldSymbol))
- {
- return;
- }
- if (filedSymbol.IsStatic)
- {
- return;
- }
- if (filedSymbol.ContainingType.BaseType?.ToString() != Definition.EntityType && filedSymbol.ContainingType.BaseType?.ToString() != Definition.LSEntityType)
- {
- return;
- }
- // -----筛选出在实体类和实体System外部字段访问-----
- // 实体System包括awakeSystem updateSystem等生命周期类和 componentSystem静态方法类
- ClassDeclarationSyntax? accessFieldClassDeclaretion = memberAccessExpressionSyntax.GetParentClassDeclaration();
- if (accessFieldClassDeclaretion == null)
- {
- return;
- }
- INamedTypeSymbol? accessFieldClassSymbol = context.SemanticModel.GetDeclaredSymbol(accessFieldClassDeclaretion);
- if (accessFieldClassSymbol == null)
- {
- return;
- }
- // 实体基类忽略处理
- if (accessFieldClassSymbol.ToString() is Definition.EntityType or Definition.LSEntityType)
- {
- return;
- }
- // 允许类内部访问字段
- if (accessFieldClassSymbol.ToString()== filedSymbol.ContainingType.ToString() )
- {
- return;
- }
-
- //判断是否在实体类生命周期System中, 这里做了修改,周期System也不允许
- //判断是否在实体类的友元类中
- if (this.CheckIsEntityFriendOf(accessFieldClassSymbol, filedSymbol.ContainingType))
- {
- return;
- }
- var builder = ImmutableDictionary.CreateBuilder<string, string?>();
- builder.Add("FriendOfType",filedSymbol.ContainingType.ToString());
- Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax.GetLocation(), builder.ToImmutable(),filedSymbol.ContainingType.ToString(),
- filedSymbol.Name);
- context.ReportDiagnostic(diagnostic);
- }
- private bool CheckIsEntityFriendOf(INamedTypeSymbol accessFieldTypeSymbol, INamedTypeSymbol entityTypeSymbol)
- {
- var attributes = accessFieldTypeSymbol.GetAttributes();
- foreach (AttributeData? attributeData in attributes)
- {
- if (!Definition.FriendAttributes.Contains(attributeData.AttributeClass?.ToString()))
- {
- continue;
- }
- if (!(attributeData.ConstructorArguments[0].Value is INamedTypeSymbol namedTypeSymbol))
- {
- continue;
- }
- if (namedTypeSymbol.ToString() == entityTypeSymbol.ToString())
- {
- return true;
- }
- }
- return false;
- }
- }
- }
|