DeviceDependentGenerator can now add suffix to the name of the generated types.

This commit is contained in:
mlemanczyk committed 2025-12-18 09:23:41 +01:00
1 parent 0b226c76e8
commit af7c9491e4
3 files changed
+41 -18

No files matched your search

@@ -9,7 +9,7 @@ namespace DeviceDependentGenerator.Tests;
public sealed class DeviceDependentGeneratorTests public sealed class DeviceDependentGeneratorTests
{ {
[Fact] [Fact]
public void Generates_classes_per_enum_value_and_filters_device_blocks() public void Generates_classes_per_enum_value_and_filters_device_blocks_with_suffix()
{ {
const string attributeAndEnum = """ const string attributeAndEnum = """
using System; using System;
@@ -19,7 +19,7 @@ public sealed class DeviceDependentGeneratorTests
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class DeviceDependentTemplateAttribute : Attribute public sealed class DeviceDependentTemplateAttribute : Attribute
{ {
public DeviceDependentTemplateAttribute(Type enumType) { } public DeviceDependentTemplateAttribute(Type enumType, string? suffix = null) { }
} }
public enum CalculationDevice public enum CalculationDevice
@@ -35,7 +35,7 @@ public sealed class DeviceDependentGeneratorTests
namespace PerfectNumbers.Core; namespace PerfectNumbers.Core;
[DeviceDependentTemplate(typeof(CalculationDevice))] [DeviceDependentTemplate(typeof(CalculationDevice), suffix: "Impl")]
public static class PrimeCalculatorTemplate public static class PrimeCalculatorTemplate
{ {
#if DEVICE_CPU #if DEVICE_CPU
@@ -65,21 +65,21 @@ public sealed class DeviceDependentGeneratorTests
ImmutableArray<GeneratedSourceResult> generated = runResult.Results.Single().GeneratedSources; ImmutableArray<GeneratedSourceResult> generated = runResult.Results.Single().GeneratedSources;
string cpu = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.Cpu.generated.cs", StringComparison.Ordinal)).SourceText.ToString(); string cpu = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.CpuImpl.generated.cs", StringComparison.Ordinal)).SourceText.ToString();
string hybrid = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.Hybrid.generated.cs", StringComparison.Ordinal)).SourceText.ToString(); string hybrid = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.HybridImpl.generated.cs", StringComparison.Ordinal)).SourceText.ToString();
string gpu = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.Gpu.generated.cs", StringComparison.Ordinal)).SourceText.ToString(); string gpu = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.GpuImpl.generated.cs", StringComparison.Ordinal)).SourceText.ToString();
cpu.Should().Contain("class PrimeCalculatorCpu"); cpu.Should().Contain("class PrimeCalculatorCpuImpl");
cpu.Should().Contain("=> \"CPU\""); cpu.Should().Contain("=> \"CPU\"");
cpu.Should().NotContain("#if"); cpu.Should().NotContain("#if");
cpu.Should().NotContain("#endif"); cpu.Should().NotContain("#endif");
hybrid.Should().Contain("class PrimeCalculatorHybrid"); hybrid.Should().Contain("class PrimeCalculatorHybridImpl");
hybrid.Should().Contain("=> \"HYBRID\""); hybrid.Should().Contain("=> \"HYBRID\"");
hybrid.Should().NotContain("#if"); hybrid.Should().NotContain("#if");
hybrid.Should().NotContain("#endif"); hybrid.Should().NotContain("#endif");
gpu.Should().Contain("class PrimeCalculatorGpu"); gpu.Should().Contain("class PrimeCalculatorGpuImpl");
gpu.Should().Contain("=> \"GPU\""); gpu.Should().Contain("=> \"GPU\"");
gpu.Should().NotContain("#if"); gpu.Should().NotContain("#if");
gpu.Should().NotContain("#endif"); gpu.Should().NotContain("#endif");
@@ -75,7 +75,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
} }
AttributeData attributeData = attributeContext.Attributes[0]; AttributeData attributeData = attributeContext.Attributes[0];
if (attributeData.ConstructorArguments.Length != 1) if (attributeData.ConstructorArguments.Length is not (1 or 2))
{ {
return null; return null;
} }
@@ -85,6 +85,23 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
return null; return null;
} }
string? suffix = null;
if (attributeData.ConstructorArguments.Length == 2)
{
suffix = attributeData.ConstructorArguments[1].Value as string;
}
if (suffix is null && attributeData.NamedArguments.Length != 0)
{
foreach (KeyValuePair<string, TypedConstant> namedArgument in attributeData.NamedArguments)
{
if (string.Equals(namedArgument.Key, "suffix", StringComparison.OrdinalIgnoreCase))
{
suffix = namedArgument.Value.Value as string;
}
}
}
if (enumTypeSymbol.TypeKind != TypeKind.Enum) if (enumTypeSymbol.TypeKind != TypeKind.Enum)
{ {
Location location = attributeContext.TargetNode.GetLocation(); Location location = attributeContext.TargetNode.GetLocation();
@@ -99,7 +116,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
.ToImmutableArray(); .ToImmutableArray();
Location attributeLocation = attributeContext.TargetNode.GetLocation(); Location attributeLocation = attributeContext.TargetNode.GetLocation();
return TemplateInfo.CreateValid(templateSymbol, enumTypeSymbol, attributeLocation, enumValues); return TemplateInfo.CreateValid(templateSymbol, enumTypeSymbol, attributeLocation, enumValues, suffix);
} }
private static void GenerateForTemplate(SourceProductionContext context, TemplateInfo template, GeneratorOptions options) private static void GenerateForTemplate(SourceProductionContext context, TemplateInfo template, GeneratorOptions options)
@@ -149,7 +166,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
continue; continue;
} }
string generatedTypeName = baseName + enumValueName; string generatedTypeName = baseName + enumValueName + template.Suffix;
TypeDeclarationSyntax generatedTypeSyntax = TransformTemplateType(deviceTemplateSyntax, generatedTypeName); TypeDeclarationSyntax generatedTypeSyntax = TransformTemplateType(deviceTemplateSyntax, generatedTypeName);
CompilationUnitSyntax generatedRoot = BuildGeneratedFile( CompilationUnitSyntax generatedRoot = BuildGeneratedFile(
@@ -161,7 +178,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
generatedRoot = (CompilationUnitSyntax)new ConditionalDirectiveAndDisabledTextStripper().Visit(generatedRoot)!; generatedRoot = (CompilationUnitSyntax)new ConditionalDirectiveAndDisabledTextStripper().Visit(generatedRoot)!;
generatedRoot = generatedRoot.NormalizeWhitespace(); generatedRoot = generatedRoot.NormalizeWhitespace();
string generatedFileName = baseName + "." + enumValueName + ".generated.cs"; string generatedFileName = baseName + "." + enumValueName + template.Suffix + ".generated.cs";
string hintName = options.BuildHintName(filePath, generatedFileName); string hintName = options.BuildHintName(filePath, generatedFileName);
context.AddSource( context.AddSource(
hintName, hintName,
@@ -280,12 +297,14 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
INamedTypeSymbol enumType, INamedTypeSymbol enumType,
Location attributeLocation, Location attributeLocation,
ImmutableArray<string> enumValues, ImmutableArray<string> enumValues,
string? suffix,
bool valid) bool valid)
{ {
TemplateType = templateType; TemplateType = templateType;
EnumType = enumType; EnumType = enumType;
AttributeLocation = attributeLocation; AttributeLocation = attributeLocation;
EnumValues = enumValues; EnumValues = enumValues;
Suffix = suffix ?? string.Empty;
Valid = valid; Valid = valid;
} }
@@ -293,6 +312,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
public INamedTypeSymbol EnumType { get; } public INamedTypeSymbol EnumType { get; }
public Location AttributeLocation { get; } public Location AttributeLocation { get; }
public ImmutableArray<string> EnumValues { get; } public ImmutableArray<string> EnumValues { get; }
public string Suffix { get; }
public bool Valid { get; } public bool Valid { get; }
public string Name => TemplateType.Name; public string Name => TemplateType.Name;
@@ -304,14 +324,15 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
public SyntaxReference? DeclaringSyntaxReference => TemplateType.DeclaringSyntaxReferences.FirstOrDefault(); public SyntaxReference? DeclaringSyntaxReference => TemplateType.DeclaringSyntaxReferences.FirstOrDefault();
public static TemplateInfo CreateInvalidEnum(INamedTypeSymbol templateType, INamedTypeSymbol enumType, Location attributeLocation) public static TemplateInfo CreateInvalidEnum(INamedTypeSymbol templateType, INamedTypeSymbol enumType, Location attributeLocation)
=> new(templateType, enumType, attributeLocation, enumValues: default, valid: false); => new(templateType, enumType, attributeLocation, enumValues: default, suffix: null, valid: false);
public static TemplateInfo CreateValid( public static TemplateInfo CreateValid(
INamedTypeSymbol templateType, INamedTypeSymbol templateType,
INamedTypeSymbol enumType, INamedTypeSymbol enumType,
Location attributeLocation, Location attributeLocation,
ImmutableArray<string> enumValues) ImmutableArray<string> enumValues,
=> new(templateType, enumType, attributeLocation, enumValues, valid: true); string? suffix)
=> new(templateType, enumType, attributeLocation, enumValues, suffix, valid: true);
} }
private readonly struct GeneratorOptions private readonly struct GeneratorOptions
@@ -5,11 +5,13 @@ namespace PerfectNumbers.Core;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class DeviceDependentTemplateAttribute : Attribute public sealed class DeviceDependentTemplateAttribute : Attribute
{ {
public DeviceDependentTemplateAttribute(Type enumType) public DeviceDependentTemplateAttribute(Type enumType, string? suffix = null)
{ {
EnumType = enumType ?? throw new ArgumentNullException(nameof(enumType)); EnumType = enumType ?? throw new ArgumentNullException(nameof(enumType));
Suffix = suffix;
} }
public Type EnumType { get; } public Type EnumType { get; }
}
public string? Suffix { get; }
}