Skip to content

Commit a999c40

Browse files
authored
Merge pull request #63734 from dotnet/oroztocil/validation-sg-fix-backport
[release/10.0] [backport fix] Fix Validation source generator deployment for non-Web SDKs
1 parent e20f294 commit a999c40

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

src/Shared/RoslynUtils/WellKnownTypes.cs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public static WellKnownTypes GetOrCreate(Compilation compilation) =>
1919

2020
private readonly INamedTypeSymbol?[] _lazyWellKnownTypes;
2121
private readonly Compilation _compilation;
22-
private readonly INamedTypeSymbol _missingTypeSymbol;
2322

2423
static WellKnownTypes()
2524
{
@@ -52,15 +51,35 @@ private WellKnownTypes(Compilation compilation)
5251
{
5352
_lazyWellKnownTypes = new INamedTypeSymbol?[WellKnownTypeData.WellKnownTypeNames.Length];
5453
_compilation = compilation;
55-
_missingTypeSymbol = compilation.GetTypeByMetadataName(typeof(MissingType).FullName!)!;
5654
}
5755

5856
public INamedTypeSymbol Get(SpecialType type)
5957
{
6058
return _compilation.GetSpecialType(type);
6159
}
6260

61+
/// <summary>
62+
/// Returns the type symbol for the specified well-known type, or throws if the type cannot be found.
63+
/// </summary>
6364
public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)
65+
{
66+
return Get(type, throwOnNotFound: true);
67+
}
68+
69+
/// <summary>
70+
/// Returns the type symbol for the specified well-known type, or a special marker type symbol if the type cannot be found.
71+
/// </summary>
72+
/// <remarks>
73+
/// We use a special marker type for cases where some types can be legitimately missing.
74+
/// E.g. The Microsoft.Extensions.Validation source generator checks against some types
75+
/// from the shared framework which are missing in Blazor WebAssembly SDK projects.
76+
/// </remarks>
77+
public INamedTypeSymbol GetOptional(WellKnownTypeData.WellKnownType type)
78+
{
79+
return Get(type, throwOnNotFound: false);
80+
}
81+
82+
private INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type, bool throwOnNotFound)
6483
{
6584
var index = (int)type;
6685
var symbol = _lazyWellKnownTypes[index];
@@ -71,12 +90,22 @@ public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)
7190

7291
// Symbol hasn't been added to the cache yet.
7392
// Resolve symbol from name, cache, and return.
74-
return GetAndCache(index);
93+
return GetAndCache(index, throwOnNotFound);
7594
}
7695

77-
private INamedTypeSymbol GetAndCache(int index)
96+
private INamedTypeSymbol GetAndCache(int index, bool throwOnNotFound)
7897
{
79-
var result = GetTypeByMetadataNameInTargetAssembly(WellKnownTypeData.WellKnownTypeNames[index]) ?? _missingTypeSymbol;
98+
var result = GetTypeByMetadataNameInTargetAssembly(WellKnownTypeData.WellKnownTypeNames[index]);
99+
100+
if (result == null && throwOnNotFound)
101+
{
102+
throw new InvalidOperationException($"Failed to resolve well-known type '{WellKnownTypeData.WellKnownTypeNames[index]}'.");
103+
}
104+
else
105+
{
106+
result ??= _compilation.GetTypeByMetadataName(typeof(MissingType).FullName!)!;
107+
}
108+
80109
Interlocked.CompareExchange(ref _lazyWellKnownTypes[index], result, null);
81110

82111
// GetTypeByMetadataName should always return the same instance for a name.

src/Validation/gen/Extensions/ITypeSymbolExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ internal static bool ImplementsInterface(this ITypeSymbol type, ITypeSymbol inte
9595
// types themselves so we short-circuit on them.
9696
internal static bool IsExemptType(this ITypeSymbol type, WellKnownTypes wellKnownTypes)
9797
{
98-
return SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpContext))
99-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpRequest))
100-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpResponse))
98+
return SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.GetOptional(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpContext))
99+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.GetOptional(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpRequest))
100+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.GetOptional(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpResponse))
101101
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_Threading_CancellationToken))
102-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormCollection))
103-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormFileCollection))
104-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormFile))
102+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.GetOptional(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormCollection))
103+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.GetOptional(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormFileCollection))
104+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.GetOptional(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormFile))
105105
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_IO_Stream))
106106
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_IO_Pipelines_PipeReader));
107107
}

src/Validation/gen/Parsers/ValidationsGenerator.TypesParser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ internal ImmutableArray<ValidatableType> ExtractValidatableTypes(IInvocationOper
2727
? method.Parameters
2828
: [];
2929

30-
var fromServiceMetadataSymbol = wellKnownTypes.Get(
30+
var fromServiceMetadataSymbol = wellKnownTypes.GetOptional(
3131
WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromServiceMetadata);
32-
var fromKeyedServiceAttributeSymbol = wellKnownTypes.Get(
32+
var fromKeyedServiceAttributeSymbol = wellKnownTypes.GetOptional(
3333
WellKnownTypeData.WellKnownType.Microsoft_Extensions_DependencyInjection_FromKeyedServicesAttribute);
3434
var skipValidationAttributeSymbol = wellKnownTypes.Get(
3535
WellKnownTypeData.WellKnownType.Microsoft_Extensions_Validation_SkipValidationAttribute);
@@ -127,9 +127,9 @@ internal ImmutableArray<ValidatableProperty> ExtractValidatableMembers(ITypeSymb
127127
var members = new List<ValidatableProperty>();
128128
var resolvedRecordProperty = new List<IPropertySymbol>();
129129

130-
var fromServiceMetadataSymbol = wellKnownTypes.Get(
130+
var fromServiceMetadataSymbol = wellKnownTypes.GetOptional(
131131
WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_Metadata_IFromServiceMetadata);
132-
var fromKeyedServiceAttributeSymbol = wellKnownTypes.Get(
132+
var fromKeyedServiceAttributeSymbol = wellKnownTypes.GetOptional(
133133
WellKnownTypeData.WellKnownType.Microsoft_Extensions_DependencyInjection_FromKeyedServicesAttribute);
134134
var jsonIgnoreAttributeSymbol = wellKnownTypes.Get(
135135
WellKnownTypeData.WellKnownType.System_Text_Json_Serialization_JsonIgnoreAttribute);

0 commit comments

Comments
 (0)