DeviceDependentGenerator added.
This commit is contained in:
1 parent
23748ad3d2
commit
9faa397364
8 files changed
+669
-4
No files matched your search
@@ -10,6 +10,10 @@ EvenPerfectBitScanner.Tests/bin/*
|
|||||||
EvenPerfectBitScanner.Tests/obj/*
|
EvenPerfectBitScanner.Tests/obj/*
|
||||||
BuildDivisorTransitions/bin/*
|
BuildDivisorTransitions/bin/*
|
||||||
BuildDivisorTransitions/obj/*
|
BuildDivisorTransitions/obj/*
|
||||||
|
DeviceDependentGenerator/bin/*
|
||||||
|
DeviceDependentGenerator/obj/*
|
||||||
|
DeviceDependentGenerator.Tests/bin/*
|
||||||
|
DeviceDependentGenerator.Tests/obj/*
|
||||||
PerfectNumbers.Core.Tests/bin/*
|
PerfectNumbers.Core.Tests/bin/*
|
||||||
PerfectNumbers.Core.Tests/obj/*
|
PerfectNumbers.Core.Tests/obj/*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\DeviceDependentGenerator\DeviceDependentGenerator.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DeviceDependentGenerator.Tests;
|
||||||
|
|
||||||
|
public sealed class DeviceDependentGeneratorTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Generates_classes_per_enum_value_and_filters_device_blocks()
|
||||||
|
{
|
||||||
|
const string attributeAndEnum = """
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
|
||||||
|
public sealed class DeviceDependentTemplateAttribute : Attribute
|
||||||
|
{
|
||||||
|
public DeviceDependentTemplateAttribute(Type enumType) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CalculationDevice
|
||||||
|
{
|
||||||
|
Cpu,
|
||||||
|
Hybrid,
|
||||||
|
Gpu,
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
const string template = """
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
|
[DeviceDependentTemplate(typeof(CalculationDevice))]
|
||||||
|
public static class PrimeCalculatorTemplate
|
||||||
|
{
|
||||||
|
#if DEVICE_CPU
|
||||||
|
public static string Device => "CPU";
|
||||||
|
#elif DEVICE_HYBRID
|
||||||
|
public static string Device => "HYBRID";
|
||||||
|
#elif DEVICE_GPU
|
||||||
|
public static string Device => "GPU";
|
||||||
|
#else
|
||||||
|
#error Unknown device
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
CSharpCompilation compilation = CreateCompilation(attributeAndEnum, template);
|
||||||
|
|
||||||
|
var generator = new PerfectNumbers.Core.Generators.DeviceDependentGenerator();
|
||||||
|
var parseOptions = (CSharpParseOptions)compilation.SyntaxTrees.First().Options;
|
||||||
|
ISourceGenerator sourceGenerator = generator.AsSourceGenerator();
|
||||||
|
GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { sourceGenerator }, parseOptions: parseOptions);
|
||||||
|
driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out _, out ImmutableArray<Diagnostic> diagnostics);
|
||||||
|
|
||||||
|
diagnostics.Should().BeEmpty();
|
||||||
|
|
||||||
|
GeneratorDriverRunResult runResult = driver.GetRunResult();
|
||||||
|
runResult.Diagnostics.Should().BeEmpty();
|
||||||
|
|
||||||
|
ImmutableArray<GeneratedSourceResult> generated = runResult.Results.Single().GeneratedSources;
|
||||||
|
|
||||||
|
string cpu = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.Cpu.generated.cs", StringComparison.Ordinal)).SourceText.ToString();
|
||||||
|
string hybrid = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.Hybrid.generated.cs", StringComparison.Ordinal)).SourceText.ToString();
|
||||||
|
string gpu = generated.Single(s => s.HintName.EndsWith("PrimeCalculator.Gpu.generated.cs", StringComparison.Ordinal)).SourceText.ToString();
|
||||||
|
|
||||||
|
cpu.Should().Contain("class PrimeCalculatorCpu");
|
||||||
|
cpu.Should().Contain("=> \"CPU\"");
|
||||||
|
cpu.Should().NotContain("#if");
|
||||||
|
cpu.Should().NotContain("#endif");
|
||||||
|
|
||||||
|
hybrid.Should().Contain("class PrimeCalculatorHybrid");
|
||||||
|
hybrid.Should().Contain("=> \"HYBRID\"");
|
||||||
|
hybrid.Should().NotContain("#if");
|
||||||
|
hybrid.Should().NotContain("#endif");
|
||||||
|
|
||||||
|
gpu.Should().Contain("class PrimeCalculatorGpu");
|
||||||
|
gpu.Should().Contain("=> \"GPU\"");
|
||||||
|
gpu.Should().NotContain("#if");
|
||||||
|
gpu.Should().NotContain("#endif");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CSharpCompilation CreateCompilation(params string[] sources)
|
||||||
|
{
|
||||||
|
var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp12);
|
||||||
|
var trees = sources.Select((text, i) => CSharpSyntaxTree.ParseText(text, parseOptions, path: "Test" + i + ".cs"));
|
||||||
|
|
||||||
|
var references = new[]
|
||||||
|
{
|
||||||
|
typeof(object),
|
||||||
|
typeof(Attribute),
|
||||||
|
typeof(Enumerable),
|
||||||
|
typeof(System.Runtime.GCSettings),
|
||||||
|
}
|
||||||
|
.Select(static t => MetadataReference.CreateFromFile(t.Assembly.Location))
|
||||||
|
.DistinctBy(static r => r.Display)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return CSharpCompilation.Create(
|
||||||
|
assemblyName: "DeviceDependentGenerator.Tests.Compilation",
|
||||||
|
syntaxTrees: trees,
|
||||||
|
references: references,
|
||||||
|
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,393 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
namespace PerfectNumbers.Core.Generators;
|
||||||
|
|
||||||
|
[Generator(LanguageNames.CSharp)]
|
||||||
|
public sealed class DeviceDependentGenerator : IIncrementalGenerator
|
||||||
|
{
|
||||||
|
private const string DeviceDependentTemplateAttributeMetadataName = "PerfectNumbers.Core.DeviceDependentTemplateAttribute";
|
||||||
|
|
||||||
|
private static readonly DiagnosticDescriptor EnumTypeMustBeEnum = new(
|
||||||
|
id: "DDG001",
|
||||||
|
title: "DeviceDependentTemplate requires an enum type",
|
||||||
|
messageFormat: "DeviceDependentTemplate requires an enum type, but '{0}' is not an enum.",
|
||||||
|
category: "DeviceDependentGenerator",
|
||||||
|
defaultSeverity: DiagnosticSeverity.Error,
|
||||||
|
isEnabledByDefault: true);
|
||||||
|
|
||||||
|
private static readonly DiagnosticDescriptor TemplateMustBeTopLevel = new(
|
||||||
|
id: "DDG002",
|
||||||
|
title: "DeviceDependentTemplate must be top-level",
|
||||||
|
messageFormat: "DeviceDependentTemplate can only be used on a top-level class/struct (not nested types).",
|
||||||
|
category: "DeviceDependentGenerator",
|
||||||
|
defaultSeverity: DiagnosticSeverity.Error,
|
||||||
|
isEnabledByDefault: true);
|
||||||
|
|
||||||
|
private static readonly DiagnosticDescriptor TemplateNotFoundInDeviceParse = new(
|
||||||
|
id: "DDG003",
|
||||||
|
title: "Template not found after preprocessing",
|
||||||
|
messageFormat: "Could not find template type '{0}' after preprocessing for device '{1}'.",
|
||||||
|
category: "DeviceDependentGenerator",
|
||||||
|
defaultSeverity: DiagnosticSeverity.Error,
|
||||||
|
isEnabledByDefault: true);
|
||||||
|
|
||||||
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
IncrementalValuesProvider<TemplateInfo> templates = context.SyntaxProvider.ForAttributeWithMetadataName(
|
||||||
|
fullyQualifiedMetadataName: DeviceDependentTemplateAttributeMetadataName,
|
||||||
|
predicate: static (node, _) => node is TypeDeclarationSyntax,
|
||||||
|
transform: static (attributeContext, cancellationToken) => TryGetTemplateInfo(attributeContext, cancellationToken))
|
||||||
|
.Where(static info => info is not null)!
|
||||||
|
.Select(static (info, _) => info!);
|
||||||
|
|
||||||
|
IncrementalValueProvider<GeneratorOptions> options = context.AnalyzerConfigOptionsProvider.Select(
|
||||||
|
static (provider, _) => new GeneratorOptions(provider.GlobalOptions));
|
||||||
|
|
||||||
|
context.RegisterSourceOutput(templates.Combine(options), static (productionContext, pair) =>
|
||||||
|
{
|
||||||
|
GenerateForTemplate(productionContext, pair.Left, pair.Right);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TemplateInfo? TryGetTemplateInfo(GeneratorAttributeSyntaxContext attributeContext, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (attributeContext.TargetSymbol is not INamedTypeSymbol templateSymbol)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributeContext.Attributes.Length != 1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeData attributeData = attributeContext.Attributes[0];
|
||||||
|
if (attributeData.ConstructorArguments.Length != 1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributeData.ConstructorArguments[0].Value is not INamedTypeSymbol enumTypeSymbol)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enumTypeSymbol.TypeKind != TypeKind.Enum)
|
||||||
|
{
|
||||||
|
Location location = attributeContext.TargetNode.GetLocation();
|
||||||
|
return TemplateInfo.CreateInvalidEnum(templateSymbol, enumTypeSymbol, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmutableArray<string> enumValues = enumTypeSymbol
|
||||||
|
.GetMembers()
|
||||||
|
.OfType<IFieldSymbol>()
|
||||||
|
.Where(static f => !f.IsImplicitlyDeclared && f.HasConstantValue)
|
||||||
|
.Select(static f => f.Name)
|
||||||
|
.ToImmutableArray();
|
||||||
|
|
||||||
|
Location attributeLocation = attributeContext.TargetNode.GetLocation();
|
||||||
|
return TemplateInfo.CreateValid(templateSymbol, enumTypeSymbol, attributeLocation, enumValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateForTemplate(SourceProductionContext context, TemplateInfo template, GeneratorOptions options)
|
||||||
|
{
|
||||||
|
if (!template.Valid)
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(EnumTypeMustBeEnum, template.AttributeLocation, template.EnumType.ToDisplayString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (template.DeclaringSyntaxReference?.GetSyntax(context.CancellationToken) is not TypeDeclarationSyntax templateSyntax)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsTopLevel(templateSyntax))
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(TemplateMustBeTopLevel, templateSyntax.Identifier.GetLocation()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string templateName = template.Name;
|
||||||
|
string baseName = templateName.EndsWith("Template", StringComparison.Ordinal)
|
||||||
|
? templateName.Substring(0, templateName.Length - "Template".Length)
|
||||||
|
: templateName;
|
||||||
|
|
||||||
|
SourceText fileText = templateSyntax.SyntaxTree.GetText(context.CancellationToken);
|
||||||
|
string filePath = templateSyntax.SyntaxTree.FilePath;
|
||||||
|
CSharpParseOptions baseParseOptions = (CSharpParseOptions)templateSyntax.SyntaxTree.Options;
|
||||||
|
|
||||||
|
foreach (string enumValueName in template.EnumValues)
|
||||||
|
{
|
||||||
|
string deviceDefine = "DEVICE_" + enumValueName.ToUpperInvariant();
|
||||||
|
CSharpParseOptions parseOptions = WithDeviceDefine(baseParseOptions, deviceDefine);
|
||||||
|
|
||||||
|
SyntaxTree deviceTree = CSharpSyntaxTree.ParseText(
|
||||||
|
fileText.ToString(),
|
||||||
|
parseOptions,
|
||||||
|
filePath,
|
||||||
|
encoding: Encoding.UTF8);
|
||||||
|
|
||||||
|
CompilationUnitSyntax deviceRoot = deviceTree.GetCompilationUnitRoot(context.CancellationToken);
|
||||||
|
TypeDeclarationSyntax? deviceTemplateSyntax = FindTemplateDeclaration(deviceRoot, templateName);
|
||||||
|
if (deviceTemplateSyntax is null)
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(TemplateNotFoundInDeviceParse, templateSyntax.Identifier.GetLocation(), templateName, enumValueName));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string generatedTypeName = baseName + enumValueName;
|
||||||
|
TypeDeclarationSyntax generatedTypeSyntax = TransformTemplateType(deviceTemplateSyntax, generatedTypeName);
|
||||||
|
|
||||||
|
CompilationUnitSyntax generatedRoot = BuildGeneratedFile(
|
||||||
|
externs: deviceRoot.Externs,
|
||||||
|
usings: deviceRoot.Usings,
|
||||||
|
containingNamespace: template.ContainingNamespace,
|
||||||
|
typeDeclaration: generatedTypeSyntax);
|
||||||
|
|
||||||
|
generatedRoot = (CompilationUnitSyntax)new ConditionalDirectiveAndDisabledTextStripper().Visit(generatedRoot)!;
|
||||||
|
generatedRoot = generatedRoot.NormalizeWhitespace();
|
||||||
|
|
||||||
|
string generatedFileName = baseName + "." + enumValueName + ".generated.cs";
|
||||||
|
string hintName = options.BuildHintName(filePath, generatedFileName);
|
||||||
|
context.AddSource(hintName, SourceText.From(generatedRoot.ToFullString(), Encoding.UTF8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsTopLevel(TypeDeclarationSyntax typeDeclaration)
|
||||||
|
=> typeDeclaration.Parent is NamespaceDeclarationSyntax
|
||||||
|
|| typeDeclaration.Parent is FileScopedNamespaceDeclarationSyntax
|
||||||
|
|| typeDeclaration.Parent is CompilationUnitSyntax;
|
||||||
|
|
||||||
|
private static CSharpParseOptions WithDeviceDefine(CSharpParseOptions baseParseOptions, string deviceDefine)
|
||||||
|
{
|
||||||
|
IEnumerable<string> symbols = baseParseOptions.PreprocessorSymbolNames;
|
||||||
|
if (symbols.Contains(deviceDefine))
|
||||||
|
{
|
||||||
|
return baseParseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseParseOptions.WithPreprocessorSymbols(symbols.Concat(new[] { deviceDefine }));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeDeclarationSyntax? FindTemplateDeclaration(CompilationUnitSyntax root, string templateName)
|
||||||
|
{
|
||||||
|
foreach (TypeDeclarationSyntax typeDecl in root.DescendantNodes().OfType<TypeDeclarationSyntax>())
|
||||||
|
{
|
||||||
|
if (string.Equals(typeDecl.Identifier.ValueText, templateName, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return typeDecl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeDeclarationSyntax TransformTemplateType(TypeDeclarationSyntax templateType, string generatedTypeName)
|
||||||
|
{
|
||||||
|
TypeDeclarationSyntax withoutAttribute = RemoveDeviceDependentAttribute(templateType);
|
||||||
|
return withoutAttribute.WithIdentifier(SyntaxFactory.Identifier(generatedTypeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeDeclarationSyntax RemoveDeviceDependentAttribute(TypeDeclarationSyntax typeDeclaration)
|
||||||
|
{
|
||||||
|
if (typeDeclaration.AttributeLists.Count == 0)
|
||||||
|
{
|
||||||
|
return typeDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newLists = new List<AttributeListSyntax>(typeDeclaration.AttributeLists.Count);
|
||||||
|
foreach (AttributeListSyntax list in typeDeclaration.AttributeLists)
|
||||||
|
{
|
||||||
|
SeparatedSyntaxList<AttributeSyntax> attributes = list.Attributes;
|
||||||
|
var newAttributes = new List<AttributeSyntax>(attributes.Count);
|
||||||
|
foreach (AttributeSyntax attribute in attributes)
|
||||||
|
{
|
||||||
|
if (IsDeviceDependentTemplateAttribute(attribute.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newAttributes.Add(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newAttributes.Count == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newLists.Add(list.WithAttributes(SyntaxFactory.SeparatedList(newAttributes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeDeclaration.WithAttributeLists(SyntaxFactory.List(newLists));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsDeviceDependentTemplateAttribute(NameSyntax attributeName)
|
||||||
|
{
|
||||||
|
string text = attributeName.ToString();
|
||||||
|
if (text.EndsWith("DeviceDependentTemplate", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.EndsWith("DeviceDependentTemplateAttribute", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CompilationUnitSyntax BuildGeneratedFile(
|
||||||
|
SyntaxList<ExternAliasDirectiveSyntax> externs,
|
||||||
|
SyntaxList<UsingDirectiveSyntax> usings,
|
||||||
|
string containingNamespace,
|
||||||
|
TypeDeclarationSyntax typeDeclaration)
|
||||||
|
{
|
||||||
|
MemberDeclarationSyntax member;
|
||||||
|
if (string.IsNullOrEmpty(containingNamespace))
|
||||||
|
{
|
||||||
|
member = typeDeclaration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
member = SyntaxFactory
|
||||||
|
.FileScopedNamespaceDeclaration(SyntaxFactory.ParseName(containingNamespace))
|
||||||
|
.WithMembers(SyntaxFactory.SingletonList<MemberDeclarationSyntax>(typeDeclaration));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SyntaxFactory
|
||||||
|
.CompilationUnit()
|
||||||
|
.WithExterns(externs)
|
||||||
|
.WithUsings(usings)
|
||||||
|
.WithMembers(SyntaxFactory.SingletonList(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TemplateInfo
|
||||||
|
{
|
||||||
|
private TemplateInfo(
|
||||||
|
INamedTypeSymbol templateType,
|
||||||
|
INamedTypeSymbol enumType,
|
||||||
|
Location attributeLocation,
|
||||||
|
ImmutableArray<string> enumValues,
|
||||||
|
bool valid)
|
||||||
|
{
|
||||||
|
TemplateType = templateType;
|
||||||
|
EnumType = enumType;
|
||||||
|
AttributeLocation = attributeLocation;
|
||||||
|
EnumValues = enumValues;
|
||||||
|
Valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public INamedTypeSymbol TemplateType { get; }
|
||||||
|
public INamedTypeSymbol EnumType { get; }
|
||||||
|
public Location AttributeLocation { get; }
|
||||||
|
public ImmutableArray<string> EnumValues { get; }
|
||||||
|
public bool Valid { get; }
|
||||||
|
|
||||||
|
public string Name => TemplateType.Name;
|
||||||
|
|
||||||
|
public string ContainingNamespace => TemplateType.ContainingNamespace?.IsGlobalNamespace == true
|
||||||
|
? string.Empty
|
||||||
|
: TemplateType.ContainingNamespace.ToDisplayString();
|
||||||
|
|
||||||
|
public SyntaxReference? DeclaringSyntaxReference => TemplateType.DeclaringSyntaxReferences.FirstOrDefault();
|
||||||
|
|
||||||
|
public static TemplateInfo CreateInvalidEnum(INamedTypeSymbol templateType, INamedTypeSymbol enumType, Location attributeLocation)
|
||||||
|
=> new(templateType, enumType, attributeLocation, enumValues: default, valid: false);
|
||||||
|
|
||||||
|
public static TemplateInfo CreateValid(
|
||||||
|
INamedTypeSymbol templateType,
|
||||||
|
INamedTypeSymbol enumType,
|
||||||
|
Location attributeLocation,
|
||||||
|
ImmutableArray<string> enumValues)
|
||||||
|
=> new(templateType, enumType, attributeLocation, enumValues, valid: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly struct GeneratorOptions
|
||||||
|
{
|
||||||
|
private readonly AnalyzerConfigOptions globalOptions;
|
||||||
|
|
||||||
|
public GeneratorOptions(AnalyzerConfigOptions globalOptions)
|
||||||
|
{
|
||||||
|
this.globalOptions = globalOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BuildHintName(string templateFilePath, string generatedFileName)
|
||||||
|
{
|
||||||
|
if (!globalOptions.TryGetValue("build_property.ProjectDir", out string? projectDir) || string.IsNullOrWhiteSpace(projectDir))
|
||||||
|
{
|
||||||
|
return generatedFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
string? templateDirectory = Path.GetDirectoryName(templateFilePath);
|
||||||
|
if (string.IsNullOrWhiteSpace(templateDirectory))
|
||||||
|
{
|
||||||
|
return generatedFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
string relativeDirectory = GetRelativePath(projectDir, templateDirectory);
|
||||||
|
if (relativeDirectory is "." or "")
|
||||||
|
{
|
||||||
|
return generatedFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeDirectory = relativeDirectory.Replace('\\', '/');
|
||||||
|
return relativeDirectory.TrimEnd('/') + "/" + generatedFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRelativePath(string baseDirectory, string targetDirectory)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(baseDirectory) || string.IsNullOrWhiteSpace(targetDirectory))
|
||||||
|
{
|
||||||
|
return targetDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!baseDirectory.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)
|
||||||
|
&& !baseDirectory.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
baseDirectory += Path.DirectorySeparatorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
var baseUri = new Uri(baseDirectory, UriKind.Absolute);
|
||||||
|
var targetUri = new Uri(targetDirectory, UriKind.Absolute);
|
||||||
|
string relative = Uri.UnescapeDataString(baseUri.MakeRelativeUri(targetUri).ToString());
|
||||||
|
return relative.Replace('/', Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class ConditionalDirectiveAndDisabledTextStripper : CSharpSyntaxRewriter
|
||||||
|
{
|
||||||
|
public override SyntaxToken VisitToken(SyntaxToken token)
|
||||||
|
=> token.WithLeadingTrivia(Filter(token.LeadingTrivia)).WithTrailingTrivia(Filter(token.TrailingTrivia));
|
||||||
|
|
||||||
|
private static SyntaxTriviaList Filter(SyntaxTriviaList list)
|
||||||
|
{
|
||||||
|
var builder = ImmutableArray.CreateBuilder<SyntaxTrivia>(list.Count);
|
||||||
|
foreach (SyntaxTrivia trivia in list)
|
||||||
|
{
|
||||||
|
SyntaxKind kind = trivia.Kind();
|
||||||
|
if (kind is SyntaxKind.DisabledTextTrivia
|
||||||
|
or SyntaxKind.IfDirectiveTrivia
|
||||||
|
or SyntaxKind.ElifDirectiveTrivia
|
||||||
|
or SyntaxKind.ElseDirectiveTrivia
|
||||||
|
or SyntaxKind.EndIfDirectiveTrivia)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Add(trivia);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SyntaxFactory.TriviaList(builder.ToImmutable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
<IsRoslynAnalyzer>true</IsRoslynAnalyzer>
|
||||||
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+93
-4
@@ -1,4 +1,5 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.0.31903.59
|
VisualStudioVersion = 17.0.31903.59
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
@@ -16,42 +17,130 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Bench
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildDivisorTransitions", "BuildDivisorTransitions\BuildDivisorTransitions.csproj", "{0A936837-5082-4C0B-AC3B-840AD2E11057}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildDivisorTransitions", "BuildDivisorTransitions\BuildDivisorTransitions.csproj", "{0A936837-5082-4C0B-AC3B-840AD2E11057}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceDependentGenerator", "DeviceDependentGenerator\DeviceDependentGenerator.csproj", "{E900CE3B-0DA4-4D7A-B825-851D6227ED67}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceDependentGenerator.Tests", "DeviceDependentGenerator.Tests\DeviceDependentGenerator.Tests.csproj", "{2C632996-9606-4CB5-B046-38AB91D6F6DC}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
Release|x64 = Release|x64
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
Release|x86 = Release|x86
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{FFD557C9-12AE-4D8D-A21A-44CEE197BFB6}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|Any CPU.Build.0 = Release|Any CPU
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{FA4063F7-CB3C-4A66-BE70-4C6535D90197}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|Any CPU.Build.0 = Release|Any CPU
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{553D1735-214B-4097-B647-D73DB2CB9ADA}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|Any CPU.Build.0 = Release|Any CPU
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{65ED9CC9-BB94-4FA5-940E-B84B3EE87DA7}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.Build.0 = Release|Any CPU
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{E900CE3B-0DA4-4D7A-B825-851D6227ED67}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{2C632996-9606-4CB5-B046-38AB91D6F6DC}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
|
||||||
|
public sealed class DeviceDependentTemplateAttribute : Attribute
|
||||||
|
{
|
||||||
|
public DeviceDependentTemplateAttribute(Type enumType)
|
||||||
|
{
|
||||||
|
EnumType = enumType ?? throw new ArgumentNullException(nameof(enumType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type EnumType { get; }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -14,6 +14,12 @@
|
|||||||
<PackageReference Include="ILGPU.Algorithms" Version="1.5.3" />
|
<PackageReference Include="ILGPU.Algorithms" Version="1.5.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\DeviceDependentGenerator\DeviceDependentGenerator.csproj"
|
||||||
|
OutputItemType="Analyzer"
|
||||||
|
ReferenceOutputAssembly="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<InternalsVisibleTo Include="EvenPerfectBitScanner.Tests" />
|
<InternalsVisibleTo Include="EvenPerfectBitScanner.Tests" />
|
||||||
<InternalsVisibleTo Include="PerfectNumbers.Core.Tests" />
|
<InternalsVisibleTo Include="PerfectNumbers.Core.Tests" />
|
||||||
|
|||||||
Reference in new issue
Block a user