diff --git a/Arch.AOT.SourceGenerator/Arch.AOT.SourceGenerator.csproj b/Arch.AOT.SourceGenerator/Arch.AOT.SourceGenerator.csproj
index 6458d69..a6bf395 100644
--- a/Arch.AOT.SourceGenerator/Arch.AOT.SourceGenerator.csproj
+++ b/Arch.AOT.SourceGenerator/Arch.AOT.SourceGenerator.csproj
@@ -13,7 +13,7 @@
Arch.AOT.SourceGenerator
Arch.AOT.SourceGenerator
- 1.0.1
+ 1.0.3-custom
genaray
Apache-2.0
A source generator for arch to support AOT.
diff --git a/Arch.AOT.SourceGenerator/Extensions/StringBuilderExtensions.cs b/Arch.AOT.SourceGenerator/Extensions/StringBuilderExtensions.cs
index 7fbac95..ca3d149 100644
--- a/Arch.AOT.SourceGenerator/Extensions/StringBuilderExtensions.cs
+++ b/Arch.AOT.SourceGenerator/Extensions/StringBuilderExtensions.cs
@@ -27,7 +27,7 @@ public static StringBuilder AppendComponentTypes(this StringBuilder sb, IList(SymbolEqualityComparer.Default);
+ var closedGenericTypes = new HashSet(SymbolEqualityComparer.Default);
+
foreach (var type in typeList)
{
// Get the symbol for the type.
var symbol = ModelExtensions.GetDeclaredSymbol(compilation.GetSemanticModel(type.SyntaxTree), type);
// If the symbol is not a type symbol, we can't do anything with it.
- if (symbol is not ITypeSymbol typeSymbol)
+ if (symbol is not INamedTypeSymbol typeSymbol)
{
continue;
}
-
- // Check if there are any fields in the type.
- var hasZeroFields = true;
- foreach (var member in typeSymbol.GetMembers())
+
+ // If the type is a generic Type definition (e.g. SomeType) we don't want to register it, we want to register their concrete usages instead.
+ if (!IsClosedType(typeSymbol))
{
- if (member is not IFieldSymbol) continue;
-
- hasZeroFields = false;
- break;
+ openGenericTypes.Add(typeSymbol);
+ continue;
}
- var typeName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- _componentTypes.Add(new ComponentType(typeName, hasZeroFields, typeSymbol.IsValueType));
+ AddComponentType(typeSymbol);
}
+
+ foreach (var tree in compilation.SyntaxTrees)
+ {
+ var semanticModel = compilation.GetSemanticModel(tree);
+ var root = tree.GetRoot();
+ foreach (var node in root.DescendantNodes().OfType())
+ {
+ if (semanticModel.GetSymbolInfo(node).Symbol is not INamedTypeSymbol typeSymbol)
+ continue;
+
+ // This is a constructed instance of a generic component
+ if (openGenericTypes.Contains(typeSymbol.OriginalDefinition) && IsClosedType(typeSymbol))
+ {
+ closedGenericTypes.Add(typeSymbol);
+ }
+ }
+ }
+
+ foreach (var typeSymbol in closedGenericTypes)
+ {
+ AddComponentType(typeSymbol);
+ }
+
sb.AppendComponentTypes(_componentTypes);
productionContext.AddSource("GeneratedComponentRegistry.g.cs",CSharpSyntaxTree.ParseText(sb.ToString()).GetRoot().NormalizeWhitespace().ToFullString());
}
+
+ private static bool IsClosedType(INamedTypeSymbol typeSymbol)
+ {
+ if (typeSymbol.IsUnboundGenericType) return false;
+ if (typeSymbol.IsGenericType)
+ {
+ return typeSymbol.TypeArguments.All(t => t.TypeKind != TypeKind.TypeParameter);
+ }
+
+ return true;
+ }
+
+ private void AddComponentType(INamedTypeSymbol typeSymbol)
+ {
+ // Check if there are any fields in the type.
+ var hasZeroFields = true;
+ foreach (var member in typeSymbol.GetMembers())
+ {
+ if (member is not IFieldSymbol) continue;
+
+ hasZeroFields = false;
+ break;
+ }
+
+ var typeName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ _componentTypes.Add(new ComponentType(typeName, hasZeroFields, typeSymbol.IsValueType));
+ }
}
\ No newline at end of file