mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 17:21:16 +08:00
refactor(analyzer): 重构上下文注册分析器中的辅助方法解析逻辑
- 修改 TryResolveArchitectureHelperMethod 和 TryResolveModuleHelperMethod 方法参数 - 添加新的 TryResolveHelperMethod 通用方法处理辅助方法调用解析 - 实现对显式 base 调用的特殊处理以保留基类语义 - 添加 IsExplicitBaseInvocation 方法检测显式基础调用 - 更新测试文件验证分析器核心行为
This commit is contained in:
parent
d2ecd14ca8
commit
37049be600
@ -466,6 +466,127 @@ public sealed class ContextRegistrationAnalyzerTests
|
||||
"""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Reports_Warning_When_Derived_Architecture_Explicitly_Calls_Base_Helper()
|
||||
{
|
||||
var markup = MarkupTestSource.Parse(
|
||||
Wrap("""
|
||||
namespace TestApp
|
||||
{
|
||||
using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.SourceGenerators.Abstractions.Rule;
|
||||
|
||||
public interface IInventoryModel : IModel { }
|
||||
|
||||
public sealed class InventoryModel : IInventoryModel { }
|
||||
|
||||
public sealed class InventoryPanelSystem : ISystem
|
||||
{
|
||||
[GetModel]
|
||||
private IInventoryModel {|#0:_model|} = null!;
|
||||
}
|
||||
|
||||
public abstract class ArchitectureBase : Architecture
|
||||
{
|
||||
protected virtual void RegisterComponents()
|
||||
{
|
||||
RegisterSystem(new InventoryPanelSystem());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GameArchitecture : ArchitectureBase
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
base.RegisterComponents();
|
||||
}
|
||||
|
||||
protected override void RegisterComponents()
|
||||
{
|
||||
RegisterModel(new InventoryModel());
|
||||
RegisterSystem(new InventoryPanelSystem());
|
||||
}
|
||||
}
|
||||
}
|
||||
"""));
|
||||
|
||||
await AnalyzerTestDriver<ContextRegistrationAnalyzer>.RunAsync(
|
||||
markup.Source,
|
||||
markup.WithSpan(
|
||||
new DiagnosticResult("GF_ContextRegistration_001", DiagnosticSeverity.Warning)
|
||||
.WithArguments("IInventoryModel", "InventoryPanelSystem", "GameArchitecture"),
|
||||
"0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Reports_Warning_When_Derived_Module_Explicitly_Calls_Base_Helper()
|
||||
{
|
||||
var markup = MarkupTestSource.Parse(
|
||||
Wrap("""
|
||||
namespace TestApp
|
||||
{
|
||||
using GFramework.Core.Abstractions.Architectures;
|
||||
using GFramework.Core.Abstractions.Model;
|
||||
using GFramework.Core.Abstractions.Systems;
|
||||
using GFramework.Core.Architectures;
|
||||
using GFramework.SourceGenerators.Abstractions.Rule;
|
||||
|
||||
public interface IInventoryModel : IModel { }
|
||||
|
||||
public sealed class InventoryModel : IInventoryModel { }
|
||||
|
||||
public sealed class InventoryPanelSystem : ISystem
|
||||
{
|
||||
[GetModel]
|
||||
private IInventoryModel {|#0:_model|} = null!;
|
||||
}
|
||||
|
||||
public abstract class ModuleBase : IArchitectureModule
|
||||
{
|
||||
public virtual void Install(IArchitecture architecture)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void RegisterComponents(IArchitecture architecture)
|
||||
{
|
||||
architecture.RegisterSystem(new InventoryPanelSystem());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DerivedInventoryModule : ModuleBase
|
||||
{
|
||||
public override void Install(IArchitecture architecture)
|
||||
{
|
||||
base.RegisterComponents(architecture);
|
||||
}
|
||||
|
||||
protected override void RegisterComponents(IArchitecture architecture)
|
||||
{
|
||||
architecture.RegisterModel(new InventoryModel());
|
||||
architecture.RegisterSystem(new InventoryPanelSystem());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
InstallModule(new DerivedInventoryModule());
|
||||
}
|
||||
}
|
||||
}
|
||||
"""));
|
||||
|
||||
await AnalyzerTestDriver<ContextRegistrationAnalyzer>.RunAsync(
|
||||
markup.Source,
|
||||
markup.WithSpan(
|
||||
new DiagnosticResult("GF_ContextRegistration_001", DiagnosticSeverity.Warning)
|
||||
.WithArguments("IInventoryModel", "InventoryPanelSystem", "GameArchitecture"),
|
||||
"0"));
|
||||
}
|
||||
|
||||
private static string Wrap(string source)
|
||||
{
|
||||
return $"{TestPreamble}{Environment.NewLine}{Environment.NewLine}{source}";
|
||||
|
||||
@ -495,7 +495,7 @@ public sealed class ContextRegistrationAnalyzer : DiagnosticAnalyzer
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryResolveArchitectureHelperMethod(invocation.TargetMethod, architectureType, out var helperMethod))
|
||||
if (TryResolveArchitectureHelperMethod(invocation, architectureType, out var helperMethod))
|
||||
pendingMethods.Enqueue(helperMethod);
|
||||
}
|
||||
}
|
||||
@ -537,7 +537,7 @@ public sealed class ContextRegistrationAnalyzer : DiagnosticAnalyzer
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryResolveModuleHelperMethod(invocation.TargetMethod, moduleType, out var helperMethod))
|
||||
if (TryResolveModuleHelperMethod(invocation, moduleType, out var helperMethod))
|
||||
pendingMethods.Enqueue(helperMethod);
|
||||
}
|
||||
}
|
||||
@ -651,38 +651,46 @@ public sealed class ContextRegistrationAnalyzer : DiagnosticAnalyzer
|
||||
}
|
||||
|
||||
private static bool TryResolveArchitectureHelperMethod(
|
||||
IMethodSymbol targetMethod,
|
||||
IInvocationOperation invocation,
|
||||
INamedTypeSymbol architectureType,
|
||||
out IMethodSymbol helperMethod)
|
||||
{
|
||||
helperMethod = default!;
|
||||
|
||||
if (targetMethod.MethodKind is not (MethodKind.Ordinary or MethodKind.Constructor))
|
||||
return false;
|
||||
|
||||
if (!SymbolHelpers.IsWithinTypeHierarchy(targetMethod.ContainingType, architectureType))
|
||||
return false;
|
||||
|
||||
// 优先解析到当前具体架构类型上的 override,只有无法映射时才回退到原始目标方法。
|
||||
helperMethod = SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, architectureType) ?? targetMethod;
|
||||
return helperMethod.DeclaringSyntaxReferences.Length > 0;
|
||||
return TryResolveHelperMethod(invocation, architectureType, out helperMethod);
|
||||
}
|
||||
|
||||
private static bool TryResolveModuleHelperMethod(
|
||||
IMethodSymbol targetMethod,
|
||||
IInvocationOperation invocation,
|
||||
INamedTypeSymbol moduleType,
|
||||
out IMethodSymbol helperMethod)
|
||||
{
|
||||
return TryResolveHelperMethod(invocation, moduleType, out helperMethod);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析架构/模块分析中的辅助方法调用。
|
||||
/// 普通虚调用应跟随到具体类型上的 override,而显式 <c>base.Xxx()</c> 必须保留基类语义。
|
||||
/// </summary>
|
||||
private static bool TryResolveHelperMethod(
|
||||
IInvocationOperation invocation,
|
||||
INamedTypeSymbol concreteType,
|
||||
out IMethodSymbol helperMethod)
|
||||
{
|
||||
helperMethod = default!;
|
||||
var targetMethod = invocation.TargetMethod;
|
||||
|
||||
if (targetMethod.MethodKind is not (MethodKind.Ordinary or MethodKind.Constructor))
|
||||
return false;
|
||||
|
||||
if (!SymbolHelpers.IsWithinTypeHierarchy(targetMethod.ContainingType, moduleType))
|
||||
if (!SymbolHelpers.IsWithinTypeHierarchy(targetMethod.ContainingType, concreteType))
|
||||
return false;
|
||||
|
||||
// 模块安装路径与架构路径一致,也必须优先跟随派生模块上的 override。
|
||||
helperMethod = SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, moduleType) ?? targetMethod;
|
||||
if (SymbolHelpers.IsExplicitBaseInvocation(invocation))
|
||||
{
|
||||
helperMethod = targetMethod;
|
||||
return helperMethod.DeclaringSyntaxReferences.Length > 0;
|
||||
}
|
||||
|
||||
helperMethod = SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, concreteType) ?? targetMethod;
|
||||
return helperMethod.DeclaringSyntaxReferences.Length > 0;
|
||||
}
|
||||
}
|
||||
@ -780,6 +788,17 @@ public sealed class ContextRegistrationAnalyzer : DiagnosticAnalyzer
|
||||
SymbolEqualityComparer.Default.Equals(type, candidateType));
|
||||
}
|
||||
|
||||
public static bool IsExplicitBaseInvocation(IInvocationOperation invocation)
|
||||
{
|
||||
return invocation.Syntax is InvocationExpressionSyntax
|
||||
{
|
||||
Expression: MemberAccessExpressionSyntax
|
||||
{
|
||||
Expression: BaseExpressionSyntax
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static IMethodSymbol? ResolveHierarchyMethodImplementation(
|
||||
IMethodSymbol method,
|
||||
INamedTypeSymbol ownerType)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user