ValidationsGenerator crashes on generic type parameters (ITypeParameterSymbol)
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Summary
The `ValidationsGenerator` source generator crashes when endpoint handler methods use generic type parameters (e.g., `TRequest` from a generic `MapCommand()` extension method). The generator emits `typeof(TRequest)` which is not valid C# in the generated code.
## Root Cause
`TryExtractValidatableType` in `ValidationsGenerator.TypesParser.cs` does not handle `ITypeParameterSymbol`. When a type parameter reaches the `DeclaredAccessibility` check, it has `Accessibility.NotApplicable`, which silently falls through. However, if the type parameter has constraints pointing to concrete validatable types, those types' properties may include the type parameter itself (e.g., CRTP pattern `RequestBase`), causing `typeof(TSelf)` to be emitted — which is not valid C#.
Two distinct issues:
1. **Type parameters are silently skipped** — generic endpoint extensions like `MapCommand(...)` where `TRequest : IValidatable` never discover the concrete validatable types reachable through constraints.
2. **Type parameters leak into emitted code** — patterns like `record CreateOrder` or CRTP `RequestBase where TSelf : RequestBase` cause `typeof(TSelf)` to appear in the generated `ValidatableInfoResolver`, producing a compilation error.
## Reproduction
```csharp
// Extension method using generic type parameter with constraint
public static class EndpointExtensions
{
public static RouteHandlerBuilder MapCommand(
this IEndpointRouteBuilder endpoints,
string pattern,
Func> handler)
where TRequest : IValidatable
{
return endpoints.MapPost(pattern, handler);
}
}
// Model with validation attributes
public class CreateOrderRequest : IValidatable
{
[Required]
public string ProductName { get; set; }
}
// Usage - generator should discover CreateOrderRequest through TRequest constraint
app.MapCommand("/orders", async (req, ct) => Results.Ok());
```
## Expected Behavior
The generator should:
1. Recognize `ITypeParameterSymbol` and walk its constraint types to discover concrete validatable types
2. Never emit `typeof(T)` where `T` is an unresolved type parameter
## Actual Behavior
The generator either:
- Silently skips the type parameter, missing validation metadata for constrained types
- Crashes with `CS0246` / `CS0103` when a type parameter leaks into `typeof()` expressions in generated code
## Proposed Fix
Handle `ITypeParameterSymbol` in `TryExtractValidatableType` by:
1. Adding it to `visitedTypes` before processing (prevents infinite recursion from circular constraints like `where T : IEnumerable`)
2. Walking `ConstraintTypes` to discover concrete validatable types
3. Adding a `ContainsTypeParameter` guard to skip properties whose type contains unresolved type parameters anywhere in the type tree (`T`, `List`, `T[]`, `Nullable`)
PR incoming.
Contributor guide
Assessment
This issue has not been assessed yet.