Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/Shared/RoslynUtils/WellKnownTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public static WellKnownTypes GetOrCreate(Compilation compilation) =>

private readonly INamedTypeSymbol?[] _lazyWellKnownTypes;
private readonly Compilation _compilation;
private readonly INamedTypeSymbol _missingTypeSymbol;

static WellKnownTypes()
{
Expand Down Expand Up @@ -51,6 +52,7 @@ private WellKnownTypes(Compilation compilation)
{
_lazyWellKnownTypes = new INamedTypeSymbol?[WellKnownTypeData.WellKnownTypeNames.Length];
_compilation = compilation;
_missingTypeSymbol = compilation.GetTypeByMetadataName(typeof(MissingType).FullName!)!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should consider reusing SpecialType.None as the fallback in this case as Roslyn does in their WellKnownType implementation (ref). That let's us reuse an existing concept instead of defining out own marker type.

Copy link
Member Author

@oroztocil oroztocil Sep 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compilation.GetSpecialType throws out-of-range exception if you try to resolve INamedTypeSymbol for SpecialType.None. The way CodeAnalysis.WellKnownTypes is set up in Roslyn, there is no actual type symbol associated with an unknown type. So if I am not overlooking something, we can't use it as a marker type for our purposes.

}

public INamedTypeSymbol Get(SpecialType type)
Expand All @@ -74,11 +76,7 @@ public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)

private INamedTypeSymbol GetAndCache(int index)
{
var result = GetTypeByMetadataNameInTargetAssembly(WellKnownTypeData.WellKnownTypeNames[index]);
if (result == null)
{
throw new InvalidOperationException($"Failed to resolve well-known type '{WellKnownTypeData.WellKnownTypeNames[index]}'.");
}
var result = GetTypeByMetadataNameInTargetAssembly(WellKnownTypeData.WellKnownTypeNames[index]) ?? _missingTypeSymbol;
Interlocked.CompareExchange(ref _lazyWellKnownTypes[index], result, null);

// GetTypeByMetadataName should always return the same instance for a name.
Expand Down Expand Up @@ -159,4 +157,6 @@ public static bool Implements(ITypeSymbol? type, ITypeSymbol interfaceType)
}
return false;
}

internal class MissingType { }
}
13 changes: 13 additions & 0 deletions src/Validation/src/Microsoft.Extensions.Validation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@
<EnableDefaultItems>true</EnableDefaultItems>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\Validation\gen\Microsoft.Extensions.Validation.ValidationsGenerator.csproj" Pack="false">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</ProjectReference>
</ItemGroup>

<ItemGroup>
<!-- Package the generator in the analyzer directory of the nuget package -->
<None Include="$(OutputPath)\$(AssemblyName).ValidationsGenerator.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>

<ItemGroup>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Reference Include="Microsoft.Extensions.Options" />
Expand Down
Loading