diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 72d9f9ea8..3fcb049c0 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -118,6 +118,11 @@ jobs:
- name: Run ComputeSharp.D2D1.Tests.AssemblyLevelAttributes
run: dotnet test tests\ComputeSharp.D2D1.Tests.AssemblyLevelAttributes\ComputeSharp.D2D1.Tests.AssemblyLevelAttributes.csproj -c Release -f ${{matrix.framework}} -v n -l "console;verbosity=detailed"
+ # Run the D2D1 source generators tests as well (only on .NET 6, like for the DX12 ones)
+ - if: matrix.framework == 'net6.0'
+ name: Run ComputeSharp.D2D1.Tests.SourceGenerators
+ run: dotnet test tests\ComputeSharp.D2D1.Tests.SourceGenerators\ComputeSharp.D2D1.Tests.SourceGenerators.csproj -v n -l "console;verbosity=detailed"
+
# Run all unit tests using D3D12MA
run-tests-d3d12ma:
needs: [build-solution]
diff --git a/ComputeSharp.sln b/ComputeSharp.sln
index a6a67a140..5094cf24c 100644
--- a/ComputeSharp.sln
+++ b/ComputeSharp.sln
@@ -156,7 +156,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.D2D1.Uwp.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputeSharp.D2D1.WinUI.Tests", "tests\ComputeSharp.D2D1.WinUI.Tests\ComputeSharp.D2D1.WinUI.Tests.csproj", "{73C32D0F-64DB-4674-84E9-8FCC41228474}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.D3D12MemoryAllocator", "src\ComputeSharp.D3D12MemoryAllocator\ComputeSharp.D3D12MemoryAllocator.csproj", "{E017B3B6-C7D3-4E53-A7F6-1036178E98C3}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputeSharp.D3D12MemoryAllocator", "src\ComputeSharp.D3D12MemoryAllocator\ComputeSharp.D3D12MemoryAllocator.csproj", "{E017B3B6-C7D3-4E53-A7F6-1036178E98C3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputeSharp.D2D1.CodeFixers", "src\ComputeSharp.D2D1.CodeFixers\ComputeSharp.D2D1.CodeFixers.csproj", "{54654960-54B5-4E19-B3ED-993591CA39E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputeSharp.D2D1.Tests.SourceGenerators", "tests\ComputeSharp.D2D1.Tests.SourceGenerators\ComputeSharp.D2D1.Tests.SourceGenerators.csproj", "{59A17380-24A0-4BD7-9012-B105A9E7D46F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -454,6 +458,22 @@ Global
{E017B3B6-C7D3-4E53-A7F6-1036178E98C3}.Release|ARM64.Build.0 = Release|Any CPU
{E017B3B6-C7D3-4E53-A7F6-1036178E98C3}.Release|x64.ActiveCfg = Release|Any CPU
{E017B3B6-C7D3-4E53-A7F6-1036178E98C3}.Release|x64.Build.0 = Release|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Debug|x64.Build.0 = Debug|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Release|ARM64.Build.0 = Release|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Release|x64.ActiveCfg = Release|Any CPU
+ {54654960-54B5-4E19-B3ED-993591CA39E5}.Release|x64.Build.0 = Release|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Debug|x64.Build.0 = Debug|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Release|ARM64.Build.0 = Release|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Release|x64.ActiveCfg = Release|Any CPU
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -494,6 +514,7 @@ Global
{346AEB10-A4EA-427E-8578-F60915DB3053} = {F8EFBB27-4EE2-4463-A75B-7EFDFB55D0F7}
{4D4BB2F6-5653-4DB5-A8DD-90D58D8FE4D3} = {F8EFBB27-4EE2-4463-A75B-7EFDFB55D0F7}
{73C32D0F-64DB-4674-84E9-8FCC41228474} = {F8EFBB27-4EE2-4463-A75B-7EFDFB55D0F7}
+ {59A17380-24A0-4BD7-9012-B105A9E7D46F} = {F8EFBB27-4EE2-4463-A75B-7EFDFB55D0F7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4664C5E3-0340-4E22-BCFD-98AAEDF5F2DC}
diff --git a/build/Directory.Build.props b/build/Directory.Build.props
index a9bcf4a60..e5dcc07eb 100644
--- a/build/Directory.Build.props
+++ b/build/Directory.Build.props
@@ -142,8 +142,12 @@
$(ProjectDirectoryPathFromSourceRoot.StartsWith('src\'))
false
true
+ false
+ true
+ false
+ true
false
- true
+ true
$(ProjectDirectoryPathFromSourceRoot.StartsWith('tests\'))
false
true
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ColorfulInfinity.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ColorfulInfinity.cs
index 94ac59d22..846712197 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ColorfulInfinity.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ColorfulInfinity.cs
@@ -11,6 +11,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct ColorfulInfinity : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ContouredLayers.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ContouredLayers.cs
index 63b01ac66..d2cf799e6 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ContouredLayers.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ContouredLayers.cs
@@ -10,6 +10,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct ContouredLayers : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/FractalTiling.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/FractalTiling.cs
index db30a226e..9b3e49957 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/FractalTiling.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/FractalTiling.cs
@@ -11,6 +11,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct FractalTiling : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/HelloWorld.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/HelloWorld.cs
index 497277206..f69707050 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/HelloWorld.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/HelloWorld.cs
@@ -9,6 +9,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct HelloWorld : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/MengerJourney.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/MengerJourney.cs
index ff9758216..ef1a0d13c 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/MengerJourney.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/MengerJourney.cs
@@ -10,6 +10,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct MengerJourney : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/Octagrams.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/Octagrams.cs
index aa16a6bba..2e83fe790 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/Octagrams.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/Octagrams.cs
@@ -10,6 +10,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct Octagrams : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ProteanClouds.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ProteanClouds.cs
index 762bf8106..00527c5c0 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ProteanClouds.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/ProteanClouds.cs
@@ -11,6 +11,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct ProteanClouds : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/PyramidPattern.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/PyramidPattern.cs
index a272f95ce..93bff4b01 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/PyramidPattern.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/PyramidPattern.cs
@@ -11,6 +11,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct PyramidPattern : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TerracedHills.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TerracedHills.cs
index 6669651c7..b45fe7c17 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TerracedHills.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TerracedHills.cs
@@ -10,6 +10,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct TerracedHills : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TriangleGridContouring.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TriangleGridContouring.cs
index 970bd7757..f2d3b62a8 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TriangleGridContouring.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TriangleGridContouring.cs
@@ -10,6 +10,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct TriangleGridContouring : ID2D1PixelShader
{
diff --git a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TwoTiledTruchet.cs b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TwoTiledTruchet.cs
index 00c763740..4e61a9a15 100644
--- a/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TwoTiledTruchet.cs
+++ b/samples/ComputeSharp.SwapChain.Shaders.D2D1.Shared/TwoTiledTruchet.cs
@@ -10,6 +10,7 @@ namespace ComputeSharp.SwapChain.Shaders.D2D1;
[D2DInputCount(0)]
[D2DRequiresScenePosition]
[D2DShaderProfile(D2D1ShaderProfile.PixelShader50)]
+[D2DGeneratedPixelShaderDescriptor]
[AutoConstructor]
internal readonly partial struct TwoTiledTruchet : ID2D1PixelShader
{
diff --git a/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj b/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj
new file mode 100644
index 000000000..41ca05c4e
--- /dev/null
+++ b/src/ComputeSharp.D2D1.CodeFixers/ComputeSharp.D2D1.CodeFixers.csproj
@@ -0,0 +1,13 @@
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ComputeSharp.D2D1.CodeFixers/MissingPixelShaderDescriptorOnPixelShaderCodeFixer.cs b/src/ComputeSharp.D2D1.CodeFixers/MissingPixelShaderDescriptorOnPixelShaderCodeFixer.cs
new file mode 100644
index 000000000..bddd91ada
--- /dev/null
+++ b/src/ComputeSharp.D2D1.CodeFixers/MissingPixelShaderDescriptorOnPixelShaderCodeFixer.cs
@@ -0,0 +1,208 @@
+using System.Collections.Immutable;
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using ComputeSharp.SourceGeneration.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Simplification;
+using Microsoft.CodeAnalysis.Text;
+using static ComputeSharp.SourceGeneration.Diagnostics.DiagnosticDescriptors;
+
+namespace ComputeSharp.D2D1.CodeFixers;
+
+///
+/// A code fixer that adds the [D2DGeneratedPixelShaderDescriptor] to D2D1 shader types with no descriptor.
+///
+[ExportCodeFixProvider(LanguageNames.CSharp)]
+[Shared]
+public sealed class MissingPixelShaderDescriptorOnPixelShaderCodeFixer : CodeFixProvider
+{
+ ///
+ /// The set of type names for all D2D attributes that can be over shader types.
+ ///
+ private static readonly ImmutableArray D2DAttributeTypeNames = ImmutableArray.Create(
+ "ComputeSharp.D2D1.D2DCompileOptionsAttribute",
+ "ComputeSharp.D2D1.D2DEffectAuthorAttribute",
+ "ComputeSharp.D2D1.D2DEffectCategoryAttribute",
+ "ComputeSharp.D2D1.D2DEffectDescriptionAttribute",
+ "ComputeSharp.D2D1.D2DEffectDisplayNameAttribute",
+ "ComputeSharp.D2D1.D2DEffectIdAttribute",
+ "ComputeSharp.D2D1.D2DInputComplexAttribute",
+ "ComputeSharp.D2D1.D2DInputCountAttribute",
+ "ComputeSharp.D2D1.D2DInputDescriptionAttribute",
+ "ComputeSharp.D2D1.D2DInputSimpleAttribute",
+ "ComputeSharp.D2D1.D2DOutputBufferAttribute",
+ "ComputeSharp.D2D1.D2DPixelOptionsAttribute",
+ "ComputeSharp.D2D1.D2DRequiresScenePositionAttribute",
+ "ComputeSharp.D2D1.D2DShaderProfileAttribute");
+
+ ///
+ public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(MissingPixelShaderDescriptorOnPixelShaderTypeId);
+
+ ///
+ public override Microsoft.CodeAnalysis.CodeFixes.FixAllProvider? GetFixAllProvider()
+ {
+ return new FixAllProvider();
+ }
+
+ ///
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ Diagnostic diagnostic = context.Diagnostics[0];
+ TextSpan diagnosticSpan = context.Span;
+
+ SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+ // Get the struct declaration from the target diagnostic
+ if (root?.FindNode(diagnosticSpan) is StructDeclarationSyntax structDeclaration)
+ {
+ // Register the code fix to update the return type to be Task instead
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ title: "Add [D2DGeneratedPixelShaderDescriptor] attribute",
+ createChangedDocument: token => AddMissingD2DGeneratedPixelShaderDescriptorAttribute(context.Document, root, structDeclaration, token),
+ equivalenceKey: "Add [D2DGeneratedPixelShaderDescriptor] attribute"),
+ diagnostic);
+ }
+ }
+
+ ///
+ /// Applies the code fix to add the [D2DGeneratedPixelShaderDescriptor] attribute to a target type.
+ ///
+ /// The original document being fixed.
+ /// The original tree root belonging to the current document.
+ /// The to update.
+ /// The cancellation token for the operation.
+ /// An updated document with the applied code fix, and the return type of the method being .
+ private static async Task AddMissingD2DGeneratedPixelShaderDescriptorAttribute(
+ Document document,
+ SyntaxNode root,
+ StructDeclarationSyntax structDeclaration,
+ CancellationToken cancellationToken)
+ {
+ // Get the new struct declaration
+ SyntaxNode updatedStructDeclaration = await AddMissingD2DGeneratedPixelShaderDescriptorAttribute(
+ document,
+ structDeclaration,
+ cancellationToken);
+
+ // Replace the node in the document tree
+ return document.WithSyntaxRoot(root.ReplaceNode(structDeclaration, updatedStructDeclaration));
+ }
+
+ ///
+ /// Applies the code fix to add the [D2DGeneratedPixelShaderDescriptor] attribute to a target type.
+ ///
+ /// The original document being fixed.
+ /// The to update.
+ /// The cancellation token for the operation.
+ /// An updated document with the applied code fix, and the return type of the method being .
+ private static async Task AddMissingD2DGeneratedPixelShaderDescriptorAttribute(
+ Document document,
+ StructDeclarationSyntax structDeclaration,
+ CancellationToken cancellationToken)
+ {
+ // Get the semantic model (bail if it's not available)
+ if (await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false) is not SemanticModel semanticModel)
+ {
+ return structDeclaration;
+ }
+
+ // Build the map of D2D attributes to look for
+ if (!semanticModel.Compilation.TryBuildNamedTypeSymbolSet(D2DAttributeTypeNames, out ImmutableHashSet? d2DAttributeTypeSymbols))
+ {
+ return structDeclaration;
+ }
+
+ // Also bail if we can't resolve the [D2DGeneratedPixelShaderDescriptor] attribute symbol (this should really never happen)
+ if (semanticModel.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.D2DGeneratedPixelShaderDescriptorAttribute") is not INamedTypeSymbol attributeSymbol)
+ {
+ return structDeclaration;
+ }
+
+ int index = 0;
+
+ // Find the index to use to insert the attribute. We want to make it so that if the struct declaration
+ // has a bunch of D2D attributes, the new one will be inserted right after that. This way the final list
+ // will be nicely sorted, instead of having D2D attributes interleaving other unrelated attributes, if any.
+ foreach (AttributeListSyntax attributeList in structDeclaration.AttributeLists)
+ {
+ // Make sure we have an attribute to check
+ if (attributeList.Attributes is not [AttributeSyntax attribute, ..])
+ {
+ continue;
+ }
+
+ // Resolve the symbol for the attribute (stop here if this failed for whatever reason)
+ if (!semanticModel.GetSymbolInfo(attribute, cancellationToken).TryGetAttributeTypeSymbol(out INamedTypeSymbol? attributeTypeSymbol))
+ {
+ break;
+ }
+
+ // If the attribute is D2D one, increment the index and continue
+ if (d2DAttributeTypeSymbols.Contains(attributeTypeSymbol))
+ {
+ index++;
+ }
+ else
+ {
+ // Otherwise, stop here, we reached the end of the sequence
+ break;
+ }
+ }
+
+ SyntaxGenerator syntaxGenerator = SyntaxGenerator.GetGenerator(document);
+
+ // Create the attribute syntax for the new attribute. Also annotate it
+ // to automatically add using directives to the document, if needed.
+ // Then create the attribute syntax and insert it at the right position.
+ SyntaxNode attributeTypeSyntax = syntaxGenerator.TypeExpression(attributeSymbol).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation);
+ SyntaxNode attributeSyntax = syntaxGenerator.Attribute(attributeTypeSyntax);
+ SyntaxNode updatedStructDeclarationSyntax = syntaxGenerator.InsertAttributes(structDeclaration, index, attributeSyntax);
+
+ // Replace the node in the syntax tree
+ return updatedStructDeclarationSyntax;
+ }
+
+ ///
+ /// A custom with the logic from .
+ ///
+ private sealed class FixAllProvider : DocumentBasedFixAllProvider
+ {
+ ///
+ protected override async Task FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray diagnostics)
+ {
+ // Get the document root (this should always succeed)
+ if (await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false) is not SyntaxNode root)
+ {
+ return document;
+ }
+
+ SyntaxEditor syntaxEditor = new(root, fixAllContext.Solution.Services);
+
+ foreach (Diagnostic diagnostic in diagnostics)
+ {
+ // Get the current struct declaration for the diagnostic
+ if (root.FindNode(diagnostic.Location.SourceSpan) is not StructDeclarationSyntax structDeclaration)
+ {
+ continue;
+ }
+
+ // Get the syntax node with the updated declaration
+ SyntaxNode updatedStructDeclaration = await AddMissingD2DGeneratedPixelShaderDescriptorAttribute(
+ document,
+ structDeclaration,
+ fixAllContext.CancellationToken);
+
+ // Replace the node via the editor
+ syntaxEditor.ReplaceNode(structDeclaration, updatedStructDeclaration);
+ }
+
+ return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot());
+ }
+ }
+}
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/AnalyzerReleases.Shipped.md b/src/ComputeSharp.D2D1.SourceGenerators/AnalyzerReleases.Shipped.md
index 7a211015b..53d2153b9 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/AnalyzerReleases.Shipped.md
+++ b/src/ComputeSharp.D2D1.SourceGenerators/AnalyzerReleases.Shipped.md
@@ -71,3 +71,5 @@ CMPSD2D0061 | ComputeSharp.D2D1.Shaders | Error | [Documentation](https://github
CMPSD2D0062 | ComputeSharp.D2D1.Shaders | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp)
CMPSD2D0063 | ComputeSharp.D2D1.Shaders | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp)
CMPSD2D0064 | ComputeSharp.D2D1.Shaders | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp)
+CMPSD2D0065 | ComputeSharp.D2D1.Shaders | Warning | [Documentation](https://github.com/Sergio0694/ComputeSharp)
+CMPSD2D0066 | ComputeSharp.D2D1.Shaders | Error | [Documentation](https://github.com/Sergio0694/ComputeSharp)
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ComputeSharp.D2D1.SourceGenerators.csproj b/src/ComputeSharp.D2D1.SourceGenerators/ComputeSharp.D2D1.SourceGenerators.csproj
index 8240a9ff3..934ad6442 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ComputeSharp.D2D1.SourceGenerators.csproj
+++ b/src/ComputeSharp.D2D1.SourceGenerators/ComputeSharp.D2D1.SourceGenerators.csproj
@@ -108,4 +108,9 @@
+
+
+
+
+
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateCreateFromConstantBufferMethod.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.CreateFromConstantBuffer.Syntax.cs
similarity index 97%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateCreateFromConstantBufferMethod.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.CreateFromConstantBuffer.Syntax.cs
index aa1be8d8b..333864120 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateCreateFromConstantBufferMethod.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.CreateFromConstantBuffer.Syntax.cs
@@ -6,7 +6,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class CreateFromConstantBuffer
@@ -21,7 +21,7 @@ public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
string typeName = info.Hierarchy.Hierarchy[0].QualifiedName;
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine("[global::System.Runtime.CompilerServices.SkipLocalsInit]");
writer.WriteLine($"readonly unsafe {typeName} global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{typeName}>.CreateFromConstantBuffer(global::System.ReadOnlySpan data)");
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectIdProperty.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectId.Syntax.cs
similarity index 97%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectIdProperty.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectId.Syntax.cs
index 1a783458f..7d4f82843 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectIdProperty.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectId.Syntax.cs
@@ -5,7 +5,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class EffectId
@@ -18,7 +18,7 @@ partial class EffectId
public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly ref readonly global::System.Guid global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.EffectId");
using (writer.WriteBlock())
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectIdProperty.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectId.cs
similarity index 99%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectIdProperty.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectId.cs
index a38c5f47d..c57150184 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectIdProperty.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectId.cs
@@ -11,7 +11,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the EffectId property.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectMetadataProperties.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectMetadata.Syntax.cs
similarity index 97%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectMetadataProperties.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectMetadata.Syntax.cs
index 860de917c..954b31662 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectMetadataProperties.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectMetadata.Syntax.cs
@@ -5,7 +5,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class EffectMetadata
@@ -60,7 +60,7 @@ public static void WriteEffectAuthorSyntax(D2D1ShaderInfo info, IndentedTextWrit
private static void WriteEffectMetadataSyntax(string qualifiedName, string propertyName, string? metadataValue, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.Write($"readonly string? global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{qualifiedName}>.{propertyName} => ");
// Append null or the metadata value as a string literal
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectMetadataProperties.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectMetadata.cs
similarity index 98%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectMetadataProperties.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectMetadata.cs
index d2158878d..5ffcb5024 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateEffectMetadataProperties.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.EffectMetadata.cs
@@ -4,7 +4,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the effect metadata properties.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslBytecodeProperties.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslBytecode.Syntax.cs
similarity index 94%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslBytecodeProperties.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslBytecode.Syntax.cs
index 6c2b84c7c..2f65635cc 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslBytecodeProperties.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslBytecode.Syntax.cs
@@ -7,7 +7,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class HlslBytecode
@@ -20,8 +20,8 @@ partial class HlslBytecode
public static void WriteShaderProfileSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
- writer.WriteLine($"readonly ComputeSharp.D2D1.D2D1ShaderProfile global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.ShaderProfile => global::ComputeSharp.D2D1.D2D1ShaderProfile.{info.HlslInfoKey.EffectiveShaderProfile};");
+ writer.WriteGeneratedAttributes(GeneratorName);
+ writer.WriteLine($"readonly ComputeSharp.D2D1.D2D1ShaderProfile global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.ShaderProfile => global::ComputeSharp.D2D1.D2D1ShaderProfile.{info.HlslInfoKey.ShaderProfile};");
}
///
@@ -33,14 +33,14 @@ public static void WriteCompileOptionsSyntax(D2D1ShaderInfo info, IndentedTextWr
{
// Get a formatted representation of the compile options being used
string compileOptionsExpression =
- info.HlslInfoKey.EffectiveCompileOptions
+ info.HlslInfoKey.CompileOptions
.ToString()
.Split(',')
.Select(static name => $"global::ComputeSharp.D2D1.D2D1CompileOptions.{name.Trim()}")
.Aggregate("", static (left, right) => left.Length > 0 ? $"{left} | {right}" : right);
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly ComputeSharp.D2D1.D2D1CompileOptions global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.CompileOptions => {compileOptionsExpression};");
}
@@ -52,7 +52,7 @@ public static void WriteCompileOptionsSyntax(D2D1ShaderInfo info, IndentedTextWr
public static void WriteHlslBytecodeSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.Write($"readonly global::System.ReadOnlyMemory global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.HlslBytecode => ");
// If there is no bytecode, just return a default expression.
@@ -98,7 +98,7 @@ static void Callback(D2D1ShaderInfo info, IndentedTextWriter writer)
writer.WriteLine($$"""/// """);
writer.WriteLine($$"""/// implementation to get the HLSL bytecode.""");
writer.WriteLine($$"""/// """);
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator), useFullyQualifiedTypeNames: false);
+ writer.WriteGeneratedAttributes(GeneratorName, useFullyQualifiedTypeNames: false);
writer.WriteLine($$"""file sealed class HlslBytecodeMemoryManager : MemoryManager""");
using (writer.WriteBlock())
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslBytecodeProperties.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslBytecode.cs
similarity index 94%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslBytecodeProperties.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslBytecode.cs
index fcf764fae..7289f8591 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslBytecodeProperties.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslBytecode.cs
@@ -18,7 +18,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the HLSL bytecode properties.
@@ -87,9 +87,13 @@ internal static partial class HlslBytecode
/// Gets the effective shader profile to use.
///
/// The requested shader profile.
+ /// Whether compilation should be performed with the input profile.
/// The effective shader profile.
- public static D2D1ShaderProfile GetEffectiveShaderProfile(D2D1ShaderProfile? shaderProfile)
+ public static D2D1ShaderProfile GetEffectiveShaderProfile(D2D1ShaderProfile? shaderProfile, out bool isCompilationEnabled)
{
+ // Compilation is only enabled if the user explicitly selected a shader profile
+ isCompilationEnabled = shaderProfile is not null;
+
// The effective shader profile is either be the requested one, or the default value (which maps to PS5.0)
return shaderProfile ?? D2D1ShaderProfile.PixelShader50;
}
@@ -150,11 +154,10 @@ public static HlslBytecodeInfo GetInfo(ref HlslBytecodeInfoKey key, Cancellation
{
static unsafe HlslBytecodeInfo GetInfo(HlslBytecodeInfoKey key, CancellationToken token)
{
- // No embedded shader was requested, or there were some errors earlier in the pipeline.
+ // Check if the compilation is not enabled (eg. if there's been errors earlier in the pipeline).
// In this case, skip the compilation, as diagnostic will be emitted for those anyway.
// Compiling would just add overhead and result in more errors, as the HLSL would be invalid.
- // We also skip compilation if no shader profile has been requested (we never just assume one).
- if (key.HasErrors || key.RequestedShaderProfile is null)
+ if (!key.IsCompilationEnabled)
{
return HlslBytecodeInfo.Missing.Instance;
}
@@ -166,8 +169,8 @@ static unsafe HlslBytecodeInfo GetInfo(HlslBytecodeInfoKey key, CancellationToke
// Compile the shader bytecode using the effective parameters
using ComPtr dxcBlobBytecode = D3DCompiler.Compile(
key.HlslSource.AsSpan(),
- key.EffectiveShaderProfile,
- key.EffectiveCompileOptions);
+ key.ShaderProfile,
+ key.CompileOptions);
token.ThrowIfCancellationRequested();
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslSourceProperty.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.Syntax.cs
similarity index 91%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslSourceProperty.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.Syntax.cs
index b065bca39..b9650bea7 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslSourceProperty.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.Syntax.cs
@@ -5,7 +5,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class HlslSource
@@ -18,7 +18,7 @@ partial class HlslSource
public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly string global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.HlslSource =>");
writer.IncreaseIndent();
writer.WriteLine("\"\"\"");
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslSourceProperty.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.cs
similarity index 99%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslSourceProperty.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.cs
index 73ece91a3..bf547c42c 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateHlslSourceProperty.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.cs
@@ -17,7 +17,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the HlslSource property.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputDescriptionsProperty.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputDescriptions.Syntax.cs
similarity index 96%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputDescriptionsProperty.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputDescriptions.Syntax.cs
index f7bde651e..c2a6b125e 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputDescriptionsProperty.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputDescriptions.Syntax.cs
@@ -7,7 +7,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
private static partial class InputDescriptions
@@ -20,7 +20,7 @@ private static partial class InputDescriptions
public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.Write($"readonly global::System.ReadOnlyMemory global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.InputDescriptions => ");
// If there are no input descriptions, just return a default expression.
@@ -66,7 +66,7 @@ static void Callback(D2D1ShaderInfo info, IndentedTextWriter writer)
writer.WriteLine($$"""/// """);
writer.WriteLine($$"""/// A container type for additional data needed by the shader.""");
writer.WriteLine($$"""/// """);
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator), useFullyQualifiedTypeNames: false);
+ writer.WriteGeneratedAttributes(GeneratorName, useFullyQualifiedTypeNames: false);
writer.WriteLine($$"""file static class Data""");
using (writer.WriteBlock())
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputDescriptionsProperty.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputDescriptions.cs
similarity index 98%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputDescriptionsProperty.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputDescriptions.cs
index dbe31d176..f6786a195 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputDescriptionsProperty.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputDescriptions.cs
@@ -10,7 +10,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the InputDescriptions property.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputTypesProperty.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputTypes.Syntax.cs
similarity index 96%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputTypesProperty.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputTypes.Syntax.cs
index 4774ef8f1..5c0255fba 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputTypesProperty.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputTypes.Syntax.cs
@@ -5,7 +5,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class InputTypes
@@ -18,7 +18,7 @@ partial class InputTypes
public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.Write($"readonly global::System.ReadOnlyMemory global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.InputTypes => ");
// If there are no inputs, simply return a default expression. Otherwise, create
@@ -65,7 +65,7 @@ static void Callback(D2D1ShaderInfo info, IndentedTextWriter writer)
writer.WriteLine($$"""/// """);
writer.WriteLine($$"""/// A implementation to get the input types.""");
writer.WriteLine($$"""/// """);
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator), useFullyQualifiedTypeNames: false);
+ writer.WriteGeneratedAttributes(GeneratorName, useFullyQualifiedTypeNames: false);
writer.WriteLine($$"""file sealed class InputTypesMemoryManager : MemoryManager""");
using (writer.WriteBlock())
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputTypesProperty.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputTypes.cs
similarity index 99%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputTypesProperty.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputTypes.cs
index 7b2d19a7e..74e902d8f 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateInputTypesProperty.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.InputTypes.cs
@@ -9,7 +9,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the InputTypes properties.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateLoadConstantBufferMethod.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.LoadConstantBuffer.Syntax.cs
similarity index 97%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateLoadConstantBufferMethod.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.LoadConstantBuffer.Syntax.cs
index 04fa769a2..a6232d492 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateLoadConstantBufferMethod.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.LoadConstantBuffer.Syntax.cs
@@ -6,7 +6,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class LoadConstantBuffer
@@ -21,7 +21,7 @@ public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
string typeName = info.Hierarchy.Hierarchy[0].QualifiedName;
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine("[global::System.Runtime.CompilerServices.SkipLocalsInit]");
writer.WriteLine($"readonly unsafe void global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{typeName}>.LoadConstantBuffer(in {typeName} shader, ref TLoader loader)");
@@ -105,7 +105,7 @@ static void Callback(D2D1ShaderInfo info, IndentedTextWriter writer)
writer.WriteLine($$"""/// """);
writer.WriteLine($$"""/// A type representing the constant buffer native layout for .""");
writer.WriteLine($$"""/// """);
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator), useFullyQualifiedTypeNames: false);
+ writer.WriteGeneratedAttributes(GeneratorName, useFullyQualifiedTypeNames: false);
writer.WriteLine($$"""[StructLayout(LayoutKind.Explicit, Size = {{info.ConstantBufferSizeInBytes}})]""");
writer.WriteLine($$"""file struct ConstantBuffer""");
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateLoadConstantBufferMethod.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.LoadConstantBuffer.cs
similarity index 99%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateLoadConstantBufferMethod.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.LoadConstantBuffer.cs
index dc12107f4..b950c73be 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateLoadConstantBufferMethod.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.LoadConstantBuffer.cs
@@ -15,7 +15,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the LoadConstantBuffer method.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateNumericProperties.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.NumericProperties.Syntax.cs
similarity index 90%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateNumericProperties.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.NumericProperties.Syntax.cs
index 4c9ca529a..a4896594b 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateNumericProperties.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.NumericProperties.Syntax.cs
@@ -5,7 +5,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the available numeric properties.
@@ -20,7 +20,7 @@ private static partial class NumericProperties
public static void WriteConstantBufferSizeSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly int global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.ConstantBufferSize => {info.ConstantBufferSizeInBytes};");
}
@@ -32,7 +32,7 @@ public static void WriteConstantBufferSizeSyntax(D2D1ShaderInfo info, IndentedTe
public static void WriteInputCountSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly int global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.InputCount => {info.InputTypes.Length};");
}
@@ -44,7 +44,7 @@ public static void WriteInputCountSyntax(D2D1ShaderInfo info, IndentedTextWriter
public static void WriteResourceTextureCountSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly int global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.ResourceTextureCount => {info.ResourceTextureDescriptions.Length};");
}
}
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateOutputBufferProperties.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.OutputBuffer.Syntax.cs
similarity index 93%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateOutputBufferProperties.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.OutputBuffer.Syntax.cs
index 6d536f8cf..3767bb783 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateOutputBufferProperties.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.OutputBuffer.Syntax.cs
@@ -6,7 +6,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class OutputBuffer
@@ -27,7 +27,7 @@ public static void WriteBufferPrecisionSyntax(D2D1ShaderInfo info, IndentedTextW
};
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly ComputeSharp.D2D1.D2D1BufferPrecision global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.BufferPrecision => {bufferPrecisionExpression};");
}
@@ -46,7 +46,7 @@ public static void WriteChannelDepthSyntax(D2D1ShaderInfo info, IndentedTextWrit
};
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly ComputeSharp.D2D1.D2D1ChannelDepth global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.ChannelDepth => {channelDepthExpression};");
}
}
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateOutputBufferProperties.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.OutputBuffer.cs
similarity index 98%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateOutputBufferProperties.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.OutputBuffer.cs
index 9c01e195c..aae4ada1b 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateOutputBufferProperties.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.OutputBuffer.cs
@@ -4,7 +4,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the output buffer properties.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreatePixelOptionsProperty.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.PixelOptions.Syntax.cs
similarity index 92%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreatePixelOptionsProperty.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.PixelOptions.Syntax.cs
index a87afa5a2..a469a3421 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreatePixelOptionsProperty.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.PixelOptions.Syntax.cs
@@ -5,7 +5,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
partial class PixelOptions
@@ -25,7 +25,7 @@ public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
};
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.WriteLine($"readonly ComputeSharp.D2D1.D2D1PixelOptions global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.PixelOptions => {pixelOptionsExpression};");
}
}
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreatePixelOptionsProperty.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.PixelOptions.cs
similarity index 95%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreatePixelOptionsProperty.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.PixelOptions.cs
index 089078150..5c9743521 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreatePixelOptionsProperty.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.PixelOptions.cs
@@ -4,7 +4,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the PixelOptions property.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateResourceTextureDescriptionsProperty.Syntax.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.ResourceTextureDescriptions.Syntax.cs
similarity index 97%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateResourceTextureDescriptionsProperty.Syntax.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.ResourceTextureDescriptions.Syntax.cs
index 94d202a3a..d0bb8a8b5 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateResourceTextureDescriptionsProperty.Syntax.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.ResourceTextureDescriptions.Syntax.cs
@@ -7,7 +7,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
private static partial class ResourceTextureDescriptions
@@ -20,7 +20,7 @@ private static partial class ResourceTextureDescriptions
public static void WriteSyntax(D2D1ShaderInfo info, IndentedTextWriter writer)
{
writer.WriteLine("/// ");
- writer.WriteGeneratedAttributes(typeof(ID2D1ShaderGenerator));
+ writer.WriteGeneratedAttributes(GeneratorName);
writer.Write($"readonly global::System.ReadOnlyMemory global::ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor<{info.Hierarchy.Hierarchy[0].QualifiedName}>.ResourceTextureDescriptions => ");
// If there are no resource texture descriptions, just return a default expression.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateResourceTextureDescriptionsProperty.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.ResourceTextureDescriptions.cs
similarity index 99%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateResourceTextureDescriptionsProperty.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.ResourceTextureDescriptions.cs
index 79dbdce9e..6282b6066 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.CreateResourceTextureDescriptionsProperty.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.ResourceTextureDescriptions.cs
@@ -11,7 +11,7 @@
namespace ComputeSharp.D2D1.SourceGenerators;
///
-partial class ID2D1ShaderGenerator
+partial class D2DPixelShaderDescriptorGenerator
{
///
/// A helper with all logic to generate the ResourceTextureDescriptions property.
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.cs b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.cs
similarity index 92%
rename from src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.cs
rename to src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.cs
index 810264f2e..9342c22ec 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.cs
@@ -5,24 +5,29 @@
using ComputeSharp.SourceGeneration.Helpers;
using ComputeSharp.SourceGeneration.Models;
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace ComputeSharp.D2D1.SourceGenerators;
///
-/// A source generator creating data loaders for the type.
+/// A source generator creating pixel shader descriptors for annotated D2D1 pixel shader types.
///
[Generator(LanguageNames.CSharp)]
-public sealed partial class ID2D1ShaderGenerator : IIncrementalGenerator
+public sealed partial class D2DPixelShaderDescriptorGenerator : IIncrementalGenerator
{
+ ///
+ /// The name of generator to include in the generated code.
+ ///
+ private const string GeneratorName = "ComputeSharp.D2D1.D2DPixelShaderDescriptorGenerator";
+
///
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Discover all shader types and extract all the necessary info from each of them
IncrementalValuesProvider shaderInfo =
context.SyntaxProvider
- .CreateSyntaxProvider(
+ .ForAttributeWithMetadataName(
+ "ComputeSharp.D2D1.D2DGeneratedPixelShaderDescriptorAttribute",
static (node, _) => node.IsTypeDeclarationWithOrPotentiallyWithBaseTypes(),
static (context, token) =>
{
@@ -32,16 +37,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return default;
}
- StructDeclarationSyntax typeDeclaration = (StructDeclarationSyntax)context.Node;
-
// If the type symbol doesn't have at least one interface, it can't possibly be a shader type
- if (context.SemanticModel.GetDeclaredSymbol(typeDeclaration, token) is not INamedTypeSymbol { AllInterfaces.Length: > 0 } typeSymbol)
+ if (context.TargetSymbol is not INamedTypeSymbol { AllInterfaces.Length: > 0 } typeSymbol)
{
return default;
}
+ StructDeclarationSyntax typeDeclaration = (StructDeclarationSyntax)context.TargetNode;
+
// Check that the shader implements the ID2D1PixelShader interface
- if (!IsD2D1PixelShaderType(typeSymbol, context.SemanticModel.Compilation))
+ if (!typeSymbol.HasInterfaceWithType(context.SemanticModel.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.ID2D1PixelShader")!))
{
return default;
}
@@ -135,9 +140,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
bool isLinkingSupported = HlslBytecode.IsSimpleInputShader(typeSymbol, inputCount);
D2D1ShaderProfile? requestedShaderProfile = HlslBytecode.GetRequestedShaderProfile(typeSymbol);
D2D1CompileOptions? requestedCompileOptions = HlslBytecode.GetRequestedCompileOptions(diagnostics, typeSymbol);
- D2D1ShaderProfile effectiveShaderProfile = HlslBytecode.GetEffectiveShaderProfile(requestedShaderProfile);
+ D2D1ShaderProfile effectiveShaderProfile = HlslBytecode.GetEffectiveShaderProfile(requestedShaderProfile, out bool isCompilationEnabled);
D2D1CompileOptions effectiveCompileOptions = HlslBytecode.GetEffectiveCompileOptions(requestedCompileOptions, isLinkingSupported);
- bool hasErrors = diagnostics.Count > 0;
token.ThrowIfCancellationRequested();
@@ -145,13 +149,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// This is done last so that it can be skipped if any errors happened before.
HlslBytecodeInfoKey hlslInfoKey = new(
hlslSource,
- requestedShaderProfile,
- requestedCompileOptions,
effectiveShaderProfile,
effectiveCompileOptions,
- hasErrors);
+ isCompilationEnabled);
- // TODO: cache this across transform runs
+ // Get the existing compiled shader, or compile the processed HLSL code
HlslBytecodeInfo hlslInfo = HlslBytecode.GetInfo(ref hlslInfoKey, token);
token.ThrowIfCancellationRequested();
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Analyzers/InvalidD2DGeneratedPixelShaderDescriptorAttributeTargetAnalyzer.cs b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Analyzers/InvalidD2DGeneratedPixelShaderDescriptorAttributeTargetAnalyzer.cs
new file mode 100644
index 000000000..4dc12f691
--- /dev/null
+++ b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Analyzers/InvalidD2DGeneratedPixelShaderDescriptorAttributeTargetAnalyzer.cs
@@ -0,0 +1,53 @@
+using System.Collections.Immutable;
+using ComputeSharp.SourceGeneration.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using static ComputeSharp.SourceGeneration.Diagnostics.DiagnosticDescriptors;
+
+namespace ComputeSharp.D2D1.SourceGenerators;
+
+///
+/// A diagnostic analyzer that generates an error whenever the [D2DGeneratedPixelShaderDescriptor] attribute is used on an invalid target type.
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+public sealed class InvalidD2DGeneratedPixelShaderDescriptorAttributeTargetAnalyzer : DiagnosticAnalyzer
+{
+ ///
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(InvalidD2DGeneratedPixelShaderDescriptorAttributeTarget);
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(static context =>
+ {
+ // Get the ID2D1PixelShader and [D2DGeneratedPixelShaderDescriptor] symbols
+ if (context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.ID2D1PixelShader") is not { } d2D1PixelShaderSymbol ||
+ context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.D2DGeneratedPixelShaderDescriptorAttribute") is not { } d2DGeneratedPixelShaderDescriptorAttributeSymbol)
+ {
+ return;
+ }
+
+ context.RegisterSymbolAction(context =>
+ {
+ // Only struct types are possible targets
+ if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Struct } typeSymbol)
+ {
+ return;
+ }
+
+ // Emit a diagnostic if the target type is using [D2DGeneratedPixelShaderDescriptor] but does not implement ID2D1PixelShader
+ if (typeSymbol.TryGetAttributeWithType(d2DGeneratedPixelShaderDescriptorAttributeSymbol, out AttributeData? attribute) &&
+ !typeSymbol.HasInterfaceWithType(d2D1PixelShaderSymbol))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ InvalidD2DGeneratedPixelShaderDescriptorAttributeTarget,
+ attribute.GetLocation(),
+ typeSymbol));
+ }
+ }, SymbolKind.NamedType);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Analyzers/MissingPixelShaderDescriptorOnPixelShaderAnalyzer.cs b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Analyzers/MissingPixelShaderDescriptorOnPixelShaderAnalyzer.cs
new file mode 100644
index 000000000..2f125cf00
--- /dev/null
+++ b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Analyzers/MissingPixelShaderDescriptorOnPixelShaderAnalyzer.cs
@@ -0,0 +1,61 @@
+using System.Collections.Immutable;
+using System.Linq;
+using ComputeSharp.SourceGeneration.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using static ComputeSharp.SourceGeneration.Diagnostics.DiagnosticDescriptors;
+
+namespace ComputeSharp.D2D1.SourceGenerators;
+
+///
+/// A diagnostic analyzer that generates a warning whenever a D2D1 shader type does not have an associated descriptor.
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+public sealed class MissingPixelShaderDescriptorOnPixelShaderAnalyzer : DiagnosticAnalyzer
+{
+ ///
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(MissingPixelShaderDescriptorOnPixelShaderType);
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(static context =>
+ {
+ // Get the ID2D1PixelShader, ID2D1PixelShaderDescriptor and [D2DGeneratedPixelShaderDescriptor] symbols
+ if (context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.ID2D1PixelShader") is not { } d2D1PixelShaderSymbol ||
+ context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.Descriptors.ID2D1PixelShaderDescriptor`1") is not { } d2D1PixelShaderDescriptorSymbol ||
+ context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.D2DGeneratedPixelShaderDescriptorAttribute") is not { } d2DGeneratedPixelShaderDescriptorAttributeSymbol)
+ {
+ return;
+ }
+
+ context.RegisterSymbolAction(context =>
+ {
+ // Only struct types are possible targets
+ if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Struct } typeSymbol)
+ {
+ return;
+ }
+
+ // If the type is not a pixel shader type, immediately bail out
+ if (!typeSymbol.HasInterfaceWithType(d2D1PixelShaderSymbol))
+ {
+ return;
+ }
+
+ // Emit a diagnostic if the descriptor is missing for the shader type
+ if (!typeSymbol.HasInterfaceWithType(d2D1PixelShaderDescriptorSymbol) &&
+ !typeSymbol.HasAttributeWithType(d2DGeneratedPixelShaderDescriptorAttributeSymbol))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ MissingPixelShaderDescriptorOnPixelShaderType,
+ typeSymbol.Locations.FirstOrDefault(),
+ typeSymbol));
+ }
+ }, SymbolKind.NamedType);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs
index a5110fe2c..7b8844205 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs
@@ -7,6 +7,11 @@ namespace ComputeSharp.SourceGeneration.Diagnostics;
///
partial class DiagnosticDescriptors
{
+ ///
+ /// The diagnostic id for .
+ ///
+ public const string MissingPixelShaderDescriptorOnPixelShaderTypeId = "CMPSD2D0065";
+
///
/// Gets a for an invalid shader field.
///
@@ -954,4 +959,37 @@ partial class DiagnosticDescriptors
description: "Unsafe blocks must be enabled for the source generators to emit valid code (the true option must be set in the .csproj/.props file).",
helpLinkUri: "https://github.com/Sergio0694/ComputeSharp",
customTags: WellKnownDiagnosticTags.CompilationEnd);
+
+ ///
+ /// Gets a for when a pixel shader type doesn't have an associated descriptor.
+ ///
+ /// Format: "The D2D1 shader of type {0} does not have an associated descriptor (it can be autogenerated via the [D2DGeneratedPixelShaderDescriptor] attribute)".
+ ///
+ ///
+ public static readonly DiagnosticDescriptor MissingPixelShaderDescriptorOnPixelShaderType = new DiagnosticDescriptor(
+ id: MissingPixelShaderDescriptorOnPixelShaderTypeId,
+ title: "Missing descriptor for D2D1 pixel shader type",
+ messageFormat: "The D2D1 shader of type {0} does not have an associated descriptor (it can be autogenerated via the [D2DGeneratedPixelShaderDescriptor] attribute)",
+ category: "ComputeSharp.D2D1.Shaders",
+ defaultSeverity: DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: "All D2D1 shader types must have an associated descriptor (it can be autogenerated via the [D2DGeneratedPixelShaderDescriptor] attribute).",
+ helpLinkUri: "https://github.com/Sergio0694/ComputeSharp",
+ customTags: WellKnownDiagnosticTags.CompilationEnd);
+
+ ///
+ /// Gets a for when the [D2DGeneratedPixelShaderDescriptor] attribute is being used on an invalid target type.
+ ///
+ /// Format: "The type {0} is not a valid target for the [D2DGeneratedPixelShaderDescriptor] attribute (only types implementing the ID2D1PixelShader interface are valid)".
+ ///
+ ///
+ public static readonly DiagnosticDescriptor InvalidD2DGeneratedPixelShaderDescriptorAttributeTarget = new DiagnosticDescriptor(
+ id: "CMPSD2D0066",
+ title: "Invalid [D2DGeneratedPixelShaderDescriptor] attribute target",
+ messageFormat: "The type {0} is not a valid target for the [D2DGeneratedPixelShaderDescriptor] attribute (only types implementing ID2D1PixelShader interface are valid)",
+ category: "ComputeSharp.D2D1.Shaders",
+ defaultSeverity: DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: "The [D2DGeneratedPixelShaderDescriptor] attribute must be used on types that implement the ID2D1PixelShader interface.",
+ helpLinkUri: "https://github.com/Sergio0694/ComputeSharp");
}
\ No newline at end of file
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Suppressors/D2D1ResourceTextureUninitializedFieldDiagnosticSuppressor.cs b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Suppressors/D2D1ResourceTextureUninitializedFieldDiagnosticSuppressor.cs
index a570e68f7..664da5675 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Suppressors/D2D1ResourceTextureUninitializedFieldDiagnosticSuppressor.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/Diagnostics/Suppressors/D2D1ResourceTextureUninitializedFieldDiagnosticSuppressor.cs
@@ -52,15 +52,13 @@ public override void ReportSuppressions(SuppressionAnalysisContext context)
HlslKnownTypes.IsResourceTextureType(fieldSymbol.Type.GetFullyQualifiedMetadataName()))
{
// Get the ID2D1PixelShader interface symbol to the check the containing type of the field
- INamedTypeSymbol? pixelShaderInterfaceSymbol = semanticModel.Compilation.GetTypeByMetadataName(typeof(ID2D1PixelShader).FullName)!;
-
- if (pixelShaderInterfaceSymbol is null)
+ if (semanticModel.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.ID2D1PixelShader") is not { } d2D1PixelShaderSymbol)
{
continue;
}
// Also check if the containing type is in fact a D2D1 pixel shader type
- if (ID2D1ShaderGenerator.IsD2D1PixelShaderType(structSymbol, semanticModel.Compilation))
+ if (structSymbol.HasInterfaceWithType(d2D1PixelShaderSymbol))
{
context.ReportSuppression(Suppression.Create(UninitializedD2D1ResourceTextureField, diagnostic));
}
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.Helpers.cs b/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.Helpers.cs
deleted file mode 100644
index ff29a0e69..000000000
--- a/src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.Helpers.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Microsoft.CodeAnalysis;
-
-namespace ComputeSharp.D2D1.SourceGenerators;
-
-///
-partial class ID2D1ShaderGenerator
-{
- ///
- /// Gets the shader type for a given shader, if any.
- ///
- /// The input instance to check.
- /// The instance currently in use.
- /// Whether or not is a D2D1 interface type.
- public static bool IsD2D1PixelShaderType(INamedTypeSymbol typeSymbol, Compilation compilation)
- {
- foreach (INamedTypeSymbol interfaceSymbol in typeSymbol.AllInterfaces)
- {
- if (interfaceSymbol.Name == nameof(ID2D1PixelShader))
- {
- INamedTypeSymbol d2D1PixelShaderSymbol = compilation.GetTypeByMetadataName("ComputeSharp.D2D1.ID2D1PixelShader")!;
-
- if (SymbolEqualityComparer.Default.Equals(interfaceSymbol, d2D1PixelShaderSymbol))
- {
- return true;
- }
- }
- }
-
- return false;
- }
-}
\ No newline at end of file
diff --git a/src/ComputeSharp.D2D1.SourceGenerators/Models/HlslBytecodeInfoKey.cs b/src/ComputeSharp.D2D1.SourceGenerators/Models/HlslBytecodeInfoKey.cs
index 772e9aea3..035f71446 100644
--- a/src/ComputeSharp.D2D1.SourceGenerators/Models/HlslBytecodeInfoKey.cs
+++ b/src/ComputeSharp.D2D1.SourceGenerators/Models/HlslBytecodeInfoKey.cs
@@ -4,15 +4,11 @@ namespace ComputeSharp.D2D1.SourceGenerators.Models;
/// A model with info to be a unique key for instances.
///
/// The input HLSL source code.
-/// The requested shader profile, if available.
-/// The requested compile options, if available.
-/// The effective shader profile.
-/// The effective compile options.
-/// Whether any errors were produced when analyzing the shader.
+/// The shader profile.
+/// The compile options.
+/// Whether compilation should be attempted for the current info.
internal sealed record HlslBytecodeInfoKey(
string HlslSource,
- D2D1ShaderProfile? RequestedShaderProfile,
- D2D1CompileOptions? RequestedCompileOptions,
- D2D1ShaderProfile EffectiveShaderProfile,
- D2D1CompileOptions EffectiveCompileOptions,
- bool HasErrors);
\ No newline at end of file
+ D2D1ShaderProfile ShaderProfile,
+ D2D1CompileOptions CompileOptions,
+ bool IsCompilationEnabled);
\ No newline at end of file
diff --git a/src/ComputeSharp.D2D1/Attributes/D2DCompileOptionsAttribute.cs b/src/ComputeSharp.D2D1/Attributes/D2DCompileOptionsAttribute.cs
index a2ef6fee2..fe4568a05 100644
--- a/src/ComputeSharp.D2D1/Attributes/D2DCompileOptionsAttribute.cs
+++ b/src/ComputeSharp.D2D1/Attributes/D2DCompileOptionsAttribute.cs
@@ -15,8 +15,6 @@ namespace ComputeSharp.D2D1;
///
///
///
-///
-///
/// Note that the is always enabled automatically and does not need to be
/// specified. This option is mandatory, as the generated code to load the constant buffer from a shader assumes the layout
/// for matrix types is row major. For the same reason, using is not
diff --git a/src/ComputeSharp.D2D1/Attributes/D2DGeneratedPixelShaderDescriptorAttribute.cs b/src/ComputeSharp.D2D1/Attributes/D2DGeneratedPixelShaderDescriptorAttribute.cs
new file mode 100644
index 000000000..da27d2fe7
--- /dev/null
+++ b/src/ComputeSharp.D2D1/Attributes/D2DGeneratedPixelShaderDescriptorAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace ComputeSharp.D2D1;
+
+///
+/// An attribute that indicates that a given D2D1 shader should have its associated descriptor code being generated.
+///
+/// This attribute can be used on shader types that are declared as :
+///
+/// [D2DGeneratedPixelShaderDescriptor]
+/// partial struct MyShader : ID2D1PixelShader
+/// {
+/// }
+///
+///
+///
+/// When a shader is annotated with , the source generator will also add
+/// to its implemented interfaces, and implement its APIs automatically.
+///
+///
+[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
+public sealed class D2DGeneratedPixelShaderDescriptorAttribute : Attribute
+{
+}
\ No newline at end of file
diff --git a/src/ComputeSharp.SourceGeneration/ComputeSharp.SourceGeneration.projitems b/src/ComputeSharp.SourceGeneration/ComputeSharp.SourceGeneration.projitems
index 3a2bf8d37..413e50cc8 100644
--- a/src/ComputeSharp.SourceGeneration/ComputeSharp.SourceGeneration.projitems
+++ b/src/ComputeSharp.SourceGeneration/ComputeSharp.SourceGeneration.projitems
@@ -18,6 +18,7 @@
+
diff --git a/src/ComputeSharp.SourceGeneration/Extensions/ISymbolExtensions.cs b/src/ComputeSharp.SourceGeneration/Extensions/ISymbolExtensions.cs
index b0a317243..a0dd6fbe3 100644
--- a/src/ComputeSharp.SourceGeneration/Extensions/ISymbolExtensions.cs
+++ b/src/ComputeSharp.SourceGeneration/Extensions/ISymbolExtensions.cs
@@ -27,6 +27,17 @@ public static string GetFullyQualifiedName(this ISymbol symbol)
return symbol.ToDisplayString(FullyQualifiedWithoutGlobalFormat);
}
+ ///
+ /// Checks whether or not a given symbol has an attribute with the specified type.
+ ///
+ /// The input instance to check.
+ /// The instance for the attribute type to look for.
+ /// Whether or not has an attribute with the specified type.
+ public static bool HasAttributeWithType(this ISymbol symbol, ITypeSymbol typeSymbol)
+ {
+ return TryGetAttributeWithType(symbol, typeSymbol, out _);
+ }
+
///
/// Tries to get an attribute with the specified type.
///
diff --git a/src/ComputeSharp.SourceGeneration/Extensions/ITypeSymbolExtensions.cs b/src/ComputeSharp.SourceGeneration/Extensions/ITypeSymbolExtensions.cs
index a9fd5b261..5149f647a 100644
--- a/src/ComputeSharp.SourceGeneration/Extensions/ITypeSymbolExtensions.cs
+++ b/src/ComputeSharp.SourceGeneration/Extensions/ITypeSymbolExtensions.cs
@@ -24,6 +24,25 @@ public static bool HasFullyQualifiedMetadataName(this ITypeSymbol symbol, string
return builder.WrittenSpan.SequenceEqual(name.AsSpan());
}
+ ///
+ /// Checks whether or not a given implements an interface of a specified type.
+ ///
+ /// The target instance to check.
+ /// The instane to check for inheritance from.
+ /// Whether or not has an interface of type .
+ public static bool HasInterfaceWithType(this ITypeSymbol typeSymbol, ITypeSymbol interfaceSymbol)
+ {
+ foreach (INamedTypeSymbol interfaceType in typeSymbol.AllInterfaces)
+ {
+ if (SymbolEqualityComparer.Default.Equals(interfaceType, interfaceSymbol))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
///
/// Gets the fully qualified metadata name for a given instance.
///
diff --git a/src/ComputeSharp.SourceGeneration/Extensions/IndentedTextWriterExtensions.cs b/src/ComputeSharp.SourceGeneration/Extensions/IndentedTextWriterExtensions.cs
index 9803e9981..262e6aa2b 100644
--- a/src/ComputeSharp.SourceGeneration/Extensions/IndentedTextWriterExtensions.cs
+++ b/src/ComputeSharp.SourceGeneration/Extensions/IndentedTextWriterExtensions.cs
@@ -17,19 +17,23 @@ internal static class IndentedTextWriterExtensions
///
///
/// The instance to write into.
- /// The type of the running generator.
+ /// The name of the generator.
/// Whether to use fully qualified type names or not.
- public static void WriteGeneratedAttributes(this IndentedTextWriter writer, Type generatorType, bool useFullyQualifiedTypeNames = true)
+ public static void WriteGeneratedAttributes(this IndentedTextWriter writer, string generatorName, bool useFullyQualifiedTypeNames = true)
{
+ // We can use this class to get the assembly, as all files for generators are just included
+ // via shared projects. As such, the assembly will be the same as the generator type itself.
+ Version assemblyVersion = typeof(IndentedTextWriterExtensions).Assembly.GetName().Version;
+
if (useFullyQualifiedTypeNames)
{
- writer.WriteLine($$"""[global::System.CodeDom.Compiler.GeneratedCode("{{generatorType.FullName}}", "{{generatorType.Assembly.GetName().Version}}")]""");
+ writer.WriteLine($$"""[global::System.CodeDom.Compiler.GeneratedCode("{{generatorName}}", "{{assemblyVersion}}")]""");
writer.WriteLine($$"""[global::System.Diagnostics.DebuggerNonUserCode]""");
writer.WriteLine($$"""[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]""");
}
else
{
- writer.WriteLine($$"""[GeneratedCode("{{generatorType.FullName}}", "{{generatorType.Assembly.GetName().Version}}")]""");
+ writer.WriteLine($$"""[GeneratedCode("{{generatorName}}", "{{assemblyVersion}}")]""");
writer.WriteLine($$"""[DebuggerNonUserCode]""");
writer.WriteLine($$"""[ExcludeFromCodeCoverage]""");
}
diff --git a/src/ComputeSharp.SourceGeneration/Extensions/SymbolInfoExtensions.cs b/src/ComputeSharp.SourceGeneration/Extensions/SymbolInfoExtensions.cs
new file mode 100644
index 000000000..2317a5d1f
--- /dev/null
+++ b/src/ComputeSharp.SourceGeneration/Extensions/SymbolInfoExtensions.cs
@@ -0,0 +1,44 @@
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.CodeAnalysis;
+
+namespace ComputeSharp.SourceGeneration.Extensions;
+
+///
+/// Extension methods for the type.
+///
+internal static class SymbolInfoExtensions
+{
+ ///
+ /// Tries to get the resolved attribute type symbol from a given value.
+ ///
+ /// The value to check.
+ /// The resulting attribute type symbol, if correctly resolved.
+ /// Whether is resolved to a symbol.
+ ///
+ /// This can be used to ensure users haven't eg. spelled names incorrecty or missed a using directive. Normally, code would just
+ /// not compile if that was the case, but that doesn't apply for attributes using invalid targets. In that case, Roslyn will ignore
+ /// any errors, meaning the generator has to validate the type symbols are correctly resolved on its own.
+ ///
+ public static bool TryGetAttributeTypeSymbol(this SymbolInfo symbolInfo, [NotNullWhen(true)] out INamedTypeSymbol? typeSymbol)
+ {
+ ISymbol? attributeSymbol = symbolInfo.Symbol;
+
+ // If no symbol is selected and there is a single candidate symbol, use that
+ if (attributeSymbol is null && symbolInfo.CandidateSymbols is [ISymbol candidateSymbol])
+ {
+ attributeSymbol = candidateSymbol;
+ }
+
+ // Extract the symbol from either the current one or the containing type
+ if ((attributeSymbol as INamedTypeSymbol ?? attributeSymbol?.ContainingType) is not INamedTypeSymbol resultingSymbol)
+ {
+ typeSymbol = null;
+
+ return false;
+ }
+
+ typeSymbol = resultingSymbol;
+
+ return true;
+ }
+}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 8395dc9ca..19fabcadd 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -45,11 +45,11 @@
-
- false
+
+ false
-
- true
+
+ true
false
@@ -76,7 +76,7 @@
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index 5fb368ada..a19860024 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -2,11 +2,18 @@
-
+
+
+
false
true
$(TargetFrameworks.Split(';')[0].Trim())
+
+
+ false
+ true
+ $(TargetFrameworks.Split(';')[0].Trim())
@@ -24,6 +31,21 @@
Visible="false" />
+
+
+
+
+
+
+
+
+
+