refactor: Remove ForEach discovery, cache MethodInfo

Remove ForEach type argument collection from source generator.
Cache MethodInfo for RemoveComponentImpl in World.cs.
Update API docs for IRelationship and ChangeKind.
This commit is contained in:
hyper
2026-07-22 16:14:58 +08:00
parent 8a32588c54
commit 53fa3b742d
3 changed files with 15 additions and 86 deletions
+3 -71
View File
@@ -53,10 +53,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
"RemoveSingleton",
};
private static readonly HashSet<string> _forEachNames = new()
{
"ForEach",
};
public void Initialize(IncrementalGeneratorInitializationContext context)
{
@@ -68,15 +65,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
.Where(t => t.FullyQualifiedName != null)
.Select((t, _) => (t.FullyQualifiedName!, t.AssemblyQualifiedName!, t.IsRelationship, t.IsSingleton));
// Also collect ForEach type arguments from the World class.
var forEachCalls = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: IsForEachCandidate,
transform: ExtractForEachTypes)
.Where(list => list.Length > 0)
.SelectMany((list, _) => list);
var allTypes = invocations.Collect().Combine(forEachCalls.Collect());
var allTypes = invocations.Collect();
context.RegisterSourceOutput(allTypes, GenerateRegistry);
}
@@ -97,21 +86,7 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
return false;
}
private static bool IsForEachCandidate(SyntaxNode node, CancellationToken _)
{
if (node is not InvocationExpressionSyntax invocation)
return false;
if (invocation.Expression is MemberAccessExpressionSyntax memberAccess)
{
var name = memberAccess.Name is GenericNameSyntax gn
? gn.Identifier.Text
: memberAccess.Name.Identifier.Text;
return _forEachNames.Contains(name);
}
return false;
}
private static (string? FullyQualifiedName, string? AssemblyQualifiedName, bool IsRelationship, bool IsSingleton) ExtractComponentType(
GeneratorSyntaxContext ctx, CancellationToken _)
@@ -154,44 +129,11 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
return (fqn, aqn, isRelationship, isSingleton);
}
private static ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> ExtractForEachTypes(
GeneratorSyntaxContext ctx, CancellationToken _)
{
if (ctx.Node is not InvocationExpressionSyntax invocation)
return ImmutableArray<(string, string, bool)>.Empty;
if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess)
return ImmutableArray<(string, string, bool)>.Empty;
if (memberAccess.Name is not GenericNameSyntax genericName)
return ImmutableArray<(string, string, bool)>.Empty;
var types = ImmutableArray.CreateBuilder<(string, string, bool)>();
foreach (var typeArg in genericName.TypeArgumentList.Arguments)
{
var symbolInfo = ctx.SemanticModel.GetSymbolInfo(typeArg);
if (symbolInfo.Symbol is INamedTypeSymbol typeSymbol &&
typeSymbol.IsValueType && !typeSymbol.IsAbstract &&
typeSymbol.DeclaredAccessibility == Accessibility.Public)
{
var fqn = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var aqn = typeSymbol.ContainingAssembly != null
? $"{typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted))}, {typeSymbol.ContainingAssembly.Name}"
: fqn;
bool isRelationship = typeSymbol.AllInterfaces.Any(i =>
i.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::OECS.IRelationship");
types.Add((fqn, aqn, isRelationship));
}
}
return types.ToImmutable();
}
private static void GenerateRegistry(SourceProductionContext context,
(ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> Left,
ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship)> Right) data)
ImmutableArray<(string FullyQualifiedName, string AssemblyQualifiedName, bool IsRelationship, bool IsSingleton)> invocations)
{
var (invocations, forEachTypes) = data;
// Collect unique types by fully-qualified name, deduplicating.
var typeMap = new Dictionary<string, (string Fqn, string Aqn, bool IsRel, bool IsSingleton)>();
@@ -202,16 +144,6 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
else
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, t.IsSingleton);
}
foreach (var t in forEachTypes)
{
if (!typeMap.ContainsKey(t.FullyQualifiedName))
typeMap[t.FullyQualifiedName] = (t.FullyQualifiedName, t.AssemblyQualifiedName, t.IsRelationship, false);
else if (t.IsRelationship)
{
var existing = typeMap[t.FullyQualifiedName];
typeMap[t.FullyQualifiedName] = (existing.Fqn, existing.Aqn, true, existing.IsSingleton);
}
}
if (typeMap.Count == 0)
return;