Skip to content

Commit

Permalink
Add annotations for Meziantou.Framework.FastEnumToStringGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
meziantou committed Nov 19, 2023
1 parent 14a6aad commit 79c7dcd
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 74 deletions.
13 changes: 10 additions & 3 deletions Meziantou.Framework.sln
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meziantou.Framework.Diagnos
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meziantou.Framework.InlineSnapshotTesting.Samples", "Samples\Meziantou.Framework.InlineSnapshotTesting.Samples\Meziantou.Framework.InlineSnapshotTesting.Samples.csproj", "{7A9F224E-CBA3-4272-97C0-0190B7125AC7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meziantou.Framework.Win32.RecentDocuments", "src\Meziantou.Framework.Win32.RecentDocuments\Meziantou.Framework.Win32.RecentDocuments.csproj", "{F2313EFC-F1BD-49EC-9CC2-0DE2CF0A1CAD}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meziantou.Framework.Win32.RecentDocuments", "src\Meziantou.Framework.Win32.RecentDocuments\Meziantou.Framework.Win32.RecentDocuments.csproj", "{F2313EFC-F1BD-49EC-9CC2-0DE2CF0A1CAD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meziantou.Framework.Win32.RecentDocumentsConsole", "Samples\Meziantou.Framework.Win32.RecentDocumentsConsole\Meziantou.Framework.Win32.RecentDocumentsConsole.csproj", "{C35AE5A4-3BD7-43F2-940D-5B0E90BF0FBF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meziantou.Framework.Win32.RecentDocumentsConsole", "Samples\Meziantou.Framework.Win32.RecentDocumentsConsole\Meziantou.Framework.Win32.RecentDocumentsConsole.csproj", "{C35AE5A4-3BD7-43F2-940D-5B0E90BF0FBF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meziantou.Framework.StronglyTypedId.Annotations", "src\Meziantou.Framework.StronglyTypedId.Annotations\Meziantou.Framework.StronglyTypedId.Annotations.csproj", "{25742DFB-FFA4-419A-85B3-F821D607A17C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meziantou.Framework.StronglyTypedId.Annotations", "src\Meziantou.Framework.StronglyTypedId.Annotations\Meziantou.Framework.StronglyTypedId.Annotations.csproj", "{25742DFB-FFA4-419A-85B3-F821D607A17C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meziantou.Framework.FastEnumToStringGenerator.Annotations", "src\Meziantou.Framework.FastEnumToStringGenerator.Annotations\Meziantou.Framework.FastEnumToStringGenerator.Annotations.csproj", "{67A21035-0C6C-4715-9CD5-260B814E52DA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -801,6 +803,10 @@ Global
{25742DFB-FFA4-419A-85B3-F821D607A17C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25742DFB-FFA4-419A-85B3-F821D607A17C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25742DFB-FFA4-419A-85B3-F821D607A17C}.Release|Any CPU.Build.0 = Release|Any CPU
{67A21035-0C6C-4715-9CD5-260B814E52DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67A21035-0C6C-4715-9CD5-260B814E52DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67A21035-0C6C-4715-9CD5-260B814E52DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67A21035-0C6C-4715-9CD5-260B814E52DA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -933,6 +939,7 @@ Global
{F2313EFC-F1BD-49EC-9CC2-0DE2CF0A1CAD} = {70A3E965-3866-4D23-9626-8D70E0E8729C}
{C35AE5A4-3BD7-43F2-940D-5B0E90BF0FBF} = {DB679A70-C2CB-4CD1-9530-D31627343FC5}
{25742DFB-FFA4-419A-85B3-F821D607A17C} = {70A3E965-3866-4D23-9626-8D70E0E8729C}
{67A21035-0C6C-4715-9CD5-260B814E52DA} = {70A3E965-3866-4D23-9626-8D70E0E8729C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AA866021-BF24-4172-A655-F0E8316C38BA}
Expand Down
30 changes: 19 additions & 11 deletions eng/validate-nuget.ps1
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
pwsh --version

# $env:NuGetDirectory= Join-Path $PSScriptRoot "../artifacts/package/debug" -Resolve
$PackagePath = (Get-ChildItem $env:NuGetDirectory | Where-Object FullName -Match "Meziantou.Framework.StronglyTypedId.[0-9.]+.nupkg").FullName
$AnnotationPath = Join-Path $PSScriptRoot ".." "src" "Meziantou.Framework.StronglyTypedId.Annotations" -Resolve
$Generators = @("Meziantou.Framework.StronglyTypedId", "Meziantou.Framework.FastEnumToStringGenerator")
foreach ($Generator in $Generators) {
Write-Host "Checking $Generator"

$Tfms = $(dotnet build --getProperty:TargetFrameworks $AnnotationPath).Split(";")
$PackagePath = (Get-ChildItem $env:NuGetDirectory | Where-Object FullName -Match "$Generator.[0-9.-]+.nupkg").FullName
$AnnotationPath = Join-Path $PSScriptRoot ".." "src" "$Generator.Annotations" -Resolve

[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
$Entries = [IO.Compression.ZipFile]::OpenRead($PackagePath).Entries.FullName
foreach ($Tfm in $Tfms) {
# Check if there is an entry with a path that starts with "lib/$Tfm/"
$Entry = $Entries | Where-Object { $_.StartsWith("lib/$Tfm/") }
if (-not $Entry) {
Write-Error "Package does not contain a lib/$Tfm/ entry"
exit 1
$Tfms = $(dotnet build --getProperty:TargetFrameworks $AnnotationPath).Split(";")

[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
$ZipFile = [IO.Compression.ZipFile]::OpenRead($PackagePath)
$Entries = $ZipFile.Entries.FullName
$ZipFile.Dispose()
foreach ($Tfm in $Tfms) {
# Check if there is an entry with a path that starts with "lib/$Tfm/"
$Entry = $Entries | Where-Object { $_.StartsWith("lib/$Tfm/") }
if (-not $Entry) {
Write-Error "Package does not contain a lib/$Tfm/ entry"
exit 1
}
}
}

Write-Host "Validating NuGet packages"
dotnet tool update Meziantou.Framework.NuGetPackageValidation.Tool --global --no-cache --add-source $env:NuGetDirectory
$files = Get-ChildItem "$env:NuGetDirectory/*" -Include *.nupkg

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Meziantou.Framework.Annotations;

[System.Diagnostics.Conditional("FastEnumToString_Attributes")]
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class FastEnumToStringAttribute : Attribute
{
public FastEnumToStringAttribute(Type enumType)
{
EnumType = enumType;
}

public bool IsPublic { get; set; } = true;
public string? ExtensionMethodNamespace { get; set; }

public Type EnumType { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LatestTargetFrameworks);netstandard2.0</TargetFrameworks>
<Description>Attributes for the Meziantou.Framework.FastEnumToStringGenerator source generator</Description>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Remove="Meziantou.Polyfill" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,8 @@ namespace Meziantou.Framework.FastEnumToStringGenerator;
[Generator]
public sealed partial class EnumToStringSourceGenerator : IIncrementalGenerator
{
[SuppressMessage("Usage", "MA0101:String contains an implicit end of line character", Justification = "Not important")]
private const string AttributeText = @"
#nullable enable
[System.Diagnostics.Conditional(""FastEnumToString_Attributes"")]
[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class FastEnumToStringAttribute : System.Attribute
{
public FastEnumToStringAttribute(System.Type enumType)
{
}
public bool IsPublic { get; set; } = true;
public string? ExtensionMethodNamespace { get; set; }
}
";

public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(ctx => ctx.AddSource("FastEnumToStringAttribute.g.cs", SourceText.From(AttributeText, Encoding.UTF8)));
var enums = context.SyntaxProvider.CreateSyntaxProvider(
predicate: static (syntax, cancellationToken) => IsSyntaxTargetForGeneration(syntax),
transform: static (ctx, cancellationToken) => GetSemanticTargetForGeneration(ctx, cancellationToken))
Expand All @@ -50,7 +33,7 @@ static bool IsSyntaxTargetForGeneration(SyntaxNode syntax)
static EnumToProcess? GetSemanticTargetForGeneration(GeneratorSyntaxContext ctx, CancellationToken cancellationToken)
{
var compilation = ctx.SemanticModel.Compilation;
var fastEnumToStringAttributeSymbol = compilation.GetTypeByMetadataName("FastEnumToStringAttribute");
var fastEnumToStringAttributeSymbol = compilation.GetTypeByMetadataName("Meziantou.Framework.Annotations.FastEnumToStringAttribute");
if (fastEnumToStringAttributeSymbol is null)
return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>$(LatestTargetFrameworks);netstandard2.0</TargetFrameworks>
<CompatibilityRecord>true</CompatibilityRecord>
<Version>1.0.8</Version>
<Version>2.0.0</Version>
<Description>Generate a faster ToString method for enumerations</Description>

<developmentDependency>true</developmentDependency>
Expand All @@ -12,7 +12,12 @@
</PropertyGroup>

<ItemGroup>
<None Include="Meziantou.Framework.FastEnumToStringGenerator.targets" Pack="true" PackagePath="build/" />
<None Include="$(OutputPath)\..\$(Configuration)_netstandard2.0\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<None Include="$(OutputPath)\..\..\Meziantou.Framework.FastEnumToStringGenerator.Annotations\$(Configuration)_netstandard2.0\*" Pack="true" PackagePath="lib/netstandard2.0" Visible="false" />
<None Include="$(OutputPath)\..\..\Meziantou.Framework.FastEnumToStringGenerator.Annotations\$(Configuration)_net6.0\*" Pack="true" PackagePath="lib/net6.0" Visible="false" />
<None Include="$(OutputPath)\..\..\Meziantou.Framework.FastEnumToStringGenerator.Annotations\$(Configuration)_net7.0\*" Pack="true" PackagePath="lib/net7.0" Visible="false" />
<None Include="$(OutputPath)\..\..\Meziantou.Framework.FastEnumToStringGenerator.Annotations\$(Configuration)_net8.0\*" Pack="true" PackagePath="lib/net8.0" Visible="false" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project>
<PropertyGroup>
<MeziantouImplicitUsings Condition="'$(MeziantouImplicitUsings)' == ''">$(ImplicitUsings)</MeziantouImplicitUsings>
</PropertyGroup>

<ItemGroup Condition="$(MeziantouImplicitUsings) == 'enable'">
<!-- For source compatibility between v1 and v2 -->
<Using Include="Meziantou.Framework.Annotations"/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Reflection;
using FluentAssertions;
using FluentAssertions.Execution;
using Meziantou.Framework.Annotations;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using TestUtilities;
Expand All @@ -13,10 +14,11 @@ public sealed class EnumToStringSourceGeneratorTests
{
private static async Task<(GeneratorDriverRunResult GeneratorResult, Compilation OutputCompilation, byte[] Assembly)> GenerateFiles(string file, bool mustCompile = true, string[] assemblyLocations = null)
{
var netcoreRef = await NuGetHelpers.GetNuGetReferences("Microsoft.NETCore.App.Ref", "5.0.0", "ref/net5.0/");
var netcoreRef = await NuGetHelpers.GetNuGetReferences("Microsoft.NETCore.App.Ref", "6.0.0", "ref/net6.0/");
assemblyLocations ??= [];
var references = assemblyLocations
.Concat(netcoreRef)
.Append(typeof(FastEnumToStringAttribute).Assembly.Location)
.Select(loc => MetadataReference.CreateFromFile(loc))
.ToArray();

Expand All @@ -41,7 +43,7 @@ public sealed class EnumToStringSourceGeneratorTests
if (mustCompile)
{
var diags = string.Join('\n', result.Diagnostics);
var generated = (await runResult.GeneratedTrees[1].GetRootAsync()).ToFullString();
var generated = (await runResult.GeneratedTrees[0].GetRootAsync()).ToFullString();
result.Success.Should().BeTrue("Project should build build:\n" + diags + "\n\n\n" + generated);
result.Diagnostics.Should().BeEmpty();
}
Expand All @@ -52,28 +54,29 @@ public sealed class EnumToStringSourceGeneratorTests
[Fact]
public async Task GenerateStructInNamespaceAndClass()
{
var sourceCode = @"
[assembly: FastEnumToStringAttribute(typeof(A.B.C.D))]
namespace A
{
namespace B
{
class C
{
public static string Sample(D value) => value.ToStringFast();
public enum D
var sourceCode = """
[assembly: Meziantou.Framework.Annotations.FastEnumToStringAttribute(typeof(A.B.C.D))]
namespace A
{
Value1,
Value2,
namespace B
{
class C
{
public static string Sample(D value) => value.ToStringFast();
public enum D
{
Value1,
Value2,
}
}
}
}
}
}
}";
""";
var (generatorResult, _, assembly) = await GenerateFiles(sourceCode);

generatorResult.Diagnostics.Should().BeEmpty();
generatorResult.GeneratedTrees.Length.Should().Be(2);
generatorResult.GeneratedTrees.Length.Should().Be(1);

var asm = Assembly.Load(assembly);
var type = asm.GetType("A.B.C");
Expand All @@ -86,33 +89,34 @@ public enum D
[Fact]
public async Task GeneratePublicType()
{
var sourceCode = @"
using SampleNs1;
[assembly: FastEnumToStringAttribute(typeof(A.B.D), IsPublic = true, ExtensionMethodNamespace = ""SampleNs1"")]
[assembly: FastEnumToStringAttribute(typeof(A.B.E), IsPublic = false, ExtensionMethodNamespace = ""SampleNs1"")]
[assembly: FastEnumToStringAttribute(typeof(A.B.F), ExtensionMethodNamespace = ""SampleNs3"")]
[assembly: FastEnumToStringAttribute(typeof(A.B.G), ExtensionMethodNamespace = ""SampleNs4"")]
var sourceCode = """
using SampleNs1;
namespace A
{
namespace B
{
public class C
{
public static string Sample(D value) => value.ToStringFast();
}
[assembly: Meziantou.Framework.Annotations.FastEnumToStringAttribute(typeof(A.B.D), IsPublic = true, ExtensionMethodNamespace = "SampleNs1")]
[assembly: Meziantou.Framework.Annotations.FastEnumToStringAttribute(typeof(A.B.E), IsPublic = false, ExtensionMethodNamespace = "SampleNs1")]
[assembly: Meziantou.Framework.Annotations.FastEnumToStringAttribute(typeof(A.B.F), ExtensionMethodNamespace = "SampleNs3")]
[assembly: Meziantou.Framework.Annotations.FastEnumToStringAttribute(typeof(A.B.G), ExtensionMethodNamespace = "SampleNs4")]
public enum D { Value1 }
public enum E { Value1 }
internal enum F { Value1 }
public enum G { Value1 }
}
}";
namespace A
{
namespace B
{
public class C
{
public static string Sample(D value) => value.ToStringFast();
}
public enum D { Value1 }
public enum E { Value1 }
internal enum F { Value1 }
public enum G { Value1 }
}
}
""";
var (generatorResult, _, assembly) = await GenerateFiles(sourceCode);

generatorResult.Diagnostics.Should().BeEmpty();
generatorResult.GeneratedTrees.Length.Should().Be(2);
generatorResult.GeneratedTrees.Length.Should().Be(1);

var asm = Assembly.Load(assembly);
var ns1Type = asm.GetType("SampleNs1.FastEnumToStringExtensions");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Meziantou.Framework.FastEnumToStringGenerator.Annotations\Meziantou.Framework.FastEnumToStringGenerator.Annotations.csproj" AdditionalProperties="TargetFramework=netstandard2.0" />
<ProjectReference Include="..\..\src\Meziantou.Framework.FastEnumToStringGenerator\Meziantou.Framework.FastEnumToStringGenerator.csproj" />
<ProjectReference Include="..\TestUtilities\TestUtilities.csproj" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.4.0" />
Expand Down

0 comments on commit 79c7dcd

Please sign in to comment.