dotnet / dotnet/aspnetcore

ValidationsGenerator crashes on generic type parameters (ITypeParameterSymbol)

Open
#65,418 7 comments 0 reactions 1 assignee Claimed by @Youssef1313 View on GitHub
area-minimal feature-validation Needs: Attention :wave:
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.