Skip to content

Commit 8708102

Browse files
committed
Use special type symbol for missing type comparisons
1 parent 0903772 commit 8708102

File tree

4 files changed

+36
-96
lines changed

4 files changed

+36
-96
lines changed

src/Shared/RoslynUtils/SymbolExtensions.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,8 @@ public static IEnumerable<ITypeSymbol> GetThisAndBaseTypes(this ITypeSymbol? typ
4949
}
5050
}
5151

52-
public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol? attributeType)
52+
public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType)
5353
{
54-
if (attributeType is null)
55-
{
56-
return false;
57-
}
58-
5954
foreach (var attributeData in symbol.GetAttributes())
6055
{
6156
if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, attributeType))
@@ -72,13 +67,8 @@ public static bool HasAttribute(this ImmutableArray<AttributeData> attributes, I
7267
return attributes.TryGetAttribute(attributeType, out _);
7368
}
7469

75-
public static bool HasAttribute(this ITypeSymbol typeSymbol, INamedTypeSymbol? attributeSymbol)
70+
public static bool HasAttribute(this ITypeSymbol typeSymbol, INamedTypeSymbol attributeSymbol)
7671
{
77-
if (attributeSymbol is null)
78-
{
79-
return false;
80-
}
81-
8272
var current = typeSymbol;
8373

8474
while (current is not null)

src/Shared/RoslynUtils/WellKnownTypes.cs

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

2020
private readonly INamedTypeSymbol?[] _lazyWellKnownTypes;
2121
private readonly Compilation _compilation;
22+
private readonly INamedTypeSymbol _missingTypeSymbol;
2223

2324
static WellKnownTypes()
2425
{
@@ -51,20 +52,16 @@ private WellKnownTypes(Compilation compilation)
5152
{
5253
_lazyWellKnownTypes = new INamedTypeSymbol?[WellKnownTypeData.WellKnownTypeNames.Length];
5354
_compilation = compilation;
55+
_missingTypeSymbol = compilation.GetTypeByMetadataName(typeof(MissingType).FullName!)!;
5456
}
5557

5658
public INamedTypeSymbol Get(SpecialType type)
5759
{
5860
return _compilation.GetSpecialType(type);
5961
}
6062

61-
public INamedTypeSymbol? Get(WellKnownTypeData.WellKnownType? type)
63+
public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)
6264
{
63-
if (type is null)
64-
{
65-
return null;
66-
}
67-
6865
var index = (int)type;
6966
var symbol = _lazyWellKnownTypes[index];
7067
if (symbol is not null)
@@ -77,18 +74,19 @@ public INamedTypeSymbol Get(SpecialType type)
7774
return GetAndCache(index);
7875
}
7976

80-
private INamedTypeSymbol? GetAndCache(int index)
77+
private INamedTypeSymbol GetAndCache(int index)
8178
{
8279
var result = GetTypeByMetadataNameInTargetAssembly(WellKnownTypeData.WellKnownTypeNames[index]);
83-
//if (result == null)
84-
//{
85-
// throw new InvalidOperationException($"Failed to resolve well-known type '{WellKnownTypeData.WellKnownTypeNames[index]}'.");
86-
//}
80+
81+
if (result is null)
82+
{
83+
result = _missingTypeSymbol;
84+
}
8785
Interlocked.CompareExchange(ref _lazyWellKnownTypes[index], result, null);
8886

8987
// GetTypeByMetadataName should always return the same instance for a name.
9088
// To ensure we have a consistent value, for thread safety, return symbol set in the array.
91-
return _lazyWellKnownTypes[index];
89+
return _lazyWellKnownTypes[index]!;
9290
}
9391

9492
// Filter for types within well-known (framework-owned) assemblies only.
@@ -135,7 +133,7 @@ public bool IsType(ITypeSymbol type, WellKnownTypeData.WellKnownType[] wellKnown
135133
return false;
136134
}
137135

138-
public bool Implements(ITypeSymbol type, WellKnownTypeData.WellKnownType?[] interfaceWellKnownTypes)
136+
public bool Implements(ITypeSymbol type, WellKnownTypeData.WellKnownType[] interfaceWellKnownTypes)
139137
{
140138
foreach (var wellKnownType in interfaceWellKnownTypes)
141139
{
@@ -148,9 +146,9 @@ public bool Implements(ITypeSymbol type, WellKnownTypeData.WellKnownType?[] inte
148146
return false;
149147
}
150148

151-
public static bool Implements(ITypeSymbol? type, ITypeSymbol? interfaceType)
149+
public static bool Implements(ITypeSymbol? type, ITypeSymbol interfaceType)
152150
{
153-
if (type is null || interfaceType is null)
151+
if (type is null)
154152
{
155153
return false;
156154
}
@@ -164,4 +162,6 @@ public static bool Implements(ITypeSymbol? type, ITypeSymbol? interfaceType)
164162
}
165163
return false;
166164
}
165+
166+
internal class MissingType { }
167167
}

src/Validation/gen/Extensions/ISymbolExtensions.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,8 @@ namespace Microsoft.Extensions.Validation;
1010

1111
internal static class ISymbolExtensions
1212
{
13-
public static string GetDisplayName(this ISymbol property, INamedTypeSymbol? displayAttribute)
13+
public static string GetDisplayName(this ISymbol property, INamedTypeSymbol displayAttribute)
1414
{
15-
if (displayAttribute is null)
16-
{
17-
return property.Name;
18-
}
19-
2015
var displayNameAttribute = property.GetAttributes()
2116
.FirstOrDefault(attribute =>
2217
attribute.AttributeClass is { } attributeClass &&

src/Validation/gen/Extensions/ITypeSymbolExtensions.cs

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
54
using System.Collections.Immutable;
65
using System.Linq;
76
using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure;
@@ -22,13 +21,8 @@ public static bool IsEnumerable(this ITypeSymbol type, INamedTypeSymbol enumerab
2221
return type.ImplementsInterface(enumerable) || SymbolEqualityComparer.Default.Equals(type, enumerable);
2322
}
2423

25-
public static bool ImplementsValidationAttribute(this ITypeSymbol typeSymbol, INamedTypeSymbol? validationAttributeSymbol)
24+
public static bool ImplementsValidationAttribute(this ITypeSymbol typeSymbol, INamedTypeSymbol validationAttributeSymbol)
2625
{
27-
if (validationAttributeSymbol is null)
28-
{
29-
return false;
30-
}
31-
3226
var baseType = typeSymbol.BaseType;
3327
while (baseType != null)
3428
{
@@ -42,9 +36,8 @@ public static bool ImplementsValidationAttribute(this ITypeSymbol typeSymbol, IN
4236
return false;
4337
}
4438

45-
public static ITypeSymbol UnwrapType(this ITypeSymbol type, INamedTypeSymbol? enumerable)
39+
public static ITypeSymbol UnwrapType(this ITypeSymbol type, INamedTypeSymbol enumerable)
4640
{
47-
4841
if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T &&
4942
type is INamedTypeSymbol { TypeArguments.Length: 1 })
5043
{
@@ -59,11 +52,6 @@ public static ITypeSymbol UnwrapType(this ITypeSymbol type, INamedTypeSymbol? en
5952
type = type.WithNullableAnnotation(NullableAnnotation.NotAnnotated);
6053
}
6154

62-
if (enumerable is null)
63-
{
64-
return type;
65-
}
66-
6755
if (type is INamedTypeSymbol namedType && namedType.IsEnumerable(enumerable) && namedType.TypeArguments.Length == 1)
6856
{
6957
// Extract the T from an IEnumerable<T> or List<T>
@@ -73,13 +61,8 @@ public static ITypeSymbol UnwrapType(this ITypeSymbol type, INamedTypeSymbol? en
7361
return type;
7462
}
7563

76-
internal static bool ImplementsInterface(this ITypeSymbol type, ITypeSymbol? interfaceType)
64+
internal static bool ImplementsInterface(this ITypeSymbol type, ITypeSymbol interfaceType)
7765
{
78-
if (interfaceType is null)
79-
{
80-
return false;
81-
}
82-
8366
foreach (var iface in type.AllInterfaces)
8467
{
8568
if (SymbolEqualityComparer.Default.Equals(interfaceType, iface))
@@ -90,13 +73,8 @@ internal static bool ImplementsInterface(this ITypeSymbol type, ITypeSymbol? int
9073
return false;
9174
}
9275

93-
internal static ImmutableArray<INamedTypeSymbol>? GetJsonDerivedTypes(this ITypeSymbol type, INamedTypeSymbol? jsonDerivedTypeAttribute)
76+
internal static ImmutableArray<INamedTypeSymbol>? GetJsonDerivedTypes(this ITypeSymbol type, INamedTypeSymbol jsonDerivedTypeAttribute)
9477
{
95-
if (jsonDerivedTypeAttribute is null)
96-
{
97-
return null;
98-
}
99-
10078
var derivedTypes = ImmutableArray.CreateBuilder<INamedTypeSymbol>();
10179
foreach (var attribute in type.GetAttributes())
10280
{
@@ -117,23 +95,15 @@ internal static bool ImplementsInterface(this ITypeSymbol type, ITypeSymbol? int
11795
// types themselves so we short-circuit on them.
11896
internal static bool IsExemptType(this ITypeSymbol type, WellKnownTypes wellKnownTypes)
11997
{
120-
try
121-
{
122-
return SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpContext))
123-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpRequest))
124-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_HttpResponse))
125-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_Threading_CancellationToken))
126-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormCollection))
127-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormFileCollection))
128-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.Microsoft_AspNetCore_Http_IFormFile))
129-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_IO_Stream))
130-
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_IO_Pipelines_PipeReader));
131-
132-
}
133-
catch (InvalidOperationException)
134-
{
135-
return false;
136-
}
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))
101+
|| 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))
105+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_IO_Stream))
106+
|| SymbolEqualityComparer.Default.Equals(type, wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_IO_Pipelines_PipeReader));
137107
}
138108

139109
internal static IPropertySymbol? FindPropertyIncludingBaseTypes(this INamedTypeSymbol typeSymbol, string propertyName)
@@ -162,13 +132,8 @@ internal static bool IsExemptType(this ITypeSymbol type, WellKnownTypes wellKnow
162132
/// <param name="parameter">The parameter to check.</param>
163133
/// <param name="fromServiceMetadataSymbol">The symbol representing the [FromService] attribute.</param>
164134
/// <param name="fromKeyedServiceAttributeSymbol">The symbol representing the [FromKeyedService] attribute.</param>
165-
internal static bool IsServiceParameter(this IParameterSymbol parameter, INamedTypeSymbol? fromServiceMetadataSymbol, INamedTypeSymbol? fromKeyedServiceAttributeSymbol)
135+
internal static bool IsServiceParameter(this IParameterSymbol parameter, INamedTypeSymbol fromServiceMetadataSymbol, INamedTypeSymbol fromKeyedServiceAttributeSymbol)
166136
{
167-
if (fromServiceMetadataSymbol is null || fromKeyedServiceAttributeSymbol is null)
168-
{
169-
return false;
170-
}
171-
172137
return parameter.GetAttributes().Any(attr =>
173138
attr.AttributeClass is not null &&
174139
(attr.AttributeClass.ImplementsInterface(fromServiceMetadataSymbol) ||
@@ -181,7 +146,7 @@ attr.AttributeClass is not null &&
181146
/// <param name="property">The property to check.</param>
182147
/// <param name="fromServiceMetadataSymbol">The symbol representing the [FromServices] attribute.</param>
183148
/// <param name="fromKeyedServiceAttributeSymbol">The symbol representing the [FromKeyedServices] attribute.</param>
184-
internal static bool IsServiceProperty(this IPropertySymbol property, INamedTypeSymbol? fromServiceMetadataSymbol, INamedTypeSymbol? fromKeyedServiceAttributeSymbol)
149+
internal static bool IsServiceProperty(this IPropertySymbol property, INamedTypeSymbol fromServiceMetadataSymbol, INamedTypeSymbol fromKeyedServiceAttributeSymbol)
185150
{
186151
if (fromServiceMetadataSymbol is null || fromKeyedServiceAttributeSymbol is null)
187152
{
@@ -199,29 +164,19 @@ attr.AttributeClass is not null &&
199164
/// </summary>
200165
/// <param name="property">The property to check.</param>
201166
/// <param name="jsonIgnoreAttributeSymbol">The symbol representing the [JsonIgnore] attribute.</param>
202-
internal static bool IsJsonIgnoredProperty(this IPropertySymbol property, INamedTypeSymbol? jsonIgnoreAttributeSymbol)
167+
internal static bool IsJsonIgnoredProperty(this IPropertySymbol property, INamedTypeSymbol jsonIgnoreAttributeSymbol)
203168
{
204-
if (jsonIgnoreAttributeSymbol is null)
205-
{
206-
return false;
207-
}
208-
209169
return property.GetAttributes().Any(attr =>
210170
attr.AttributeClass is not null &&
211171
SymbolEqualityComparer.Default.Equals(attr.AttributeClass, jsonIgnoreAttributeSymbol));
212172
}
213173

214-
internal static bool IsSkippedValidationProperty(this IPropertySymbol property, INamedTypeSymbol? skipValidationAttributeSymbol)
174+
internal static bool IsSkippedValidationProperty(this IPropertySymbol property, INamedTypeSymbol skipValidationAttributeSymbol)
215175
{
216-
if (skipValidationAttributeSymbol is null)
217-
{
218-
return false;
219-
}
220-
221176
return property.HasAttribute(skipValidationAttributeSymbol) || property.Type.HasAttribute(skipValidationAttributeSymbol);
222177
}
223178

224-
internal static bool IsSkippedValidationParameter(this IParameterSymbol parameter, INamedTypeSymbol? skipValidationAttributeSymbol)
179+
internal static bool IsSkippedValidationParameter(this IParameterSymbol parameter, INamedTypeSymbol skipValidationAttributeSymbol)
225180
{
226181
return parameter.HasAttribute(skipValidationAttributeSymbol) || parameter.Type.HasAttribute(skipValidationAttributeSymbol);
227182
}

0 commit comments

Comments
 (0)