Skip to content

Commit 0a7e34a

Browse files
committed
update Microsoft.CodeAnalysis.CSharp v5.0.0 and add [Embedded] attribute
1 parent 2a6e164 commit 0a7e34a

File tree

5 files changed

+241
-31
lines changed

5 files changed

+241
-31
lines changed

src/ToonEncoder.Generator/ToonEncoder.Generator.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@
1515
</PropertyGroup>
1616

1717
<ItemGroup>
18-
<!-- Roslyn for .NET 8 / C# 12 -->
19-
<!-- https://learn.microsoft.com/en-us/visualstudio/extensibility/roslyn-version-support -->
20-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
18+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" />
2119
<PackageReference Include="PolySharp" Version="1.15.0">
2220
<PrivateAssets>all</PrivateAssets>
2321
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

src/ToonEncoder.Generator/ToonEncoderGenerator.cs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
1212
{
1313
context.RegisterPostInitializationOutput(EmitAttributes);
1414

15-
var tabularArray = context.SyntaxProvider.ForAttributeWithMetadataName("Cysharp.AI.GenerateToonTabularArrayConverter",
15+
var tabularArray = context.SyntaxProvider.ForAttributeWithMetadataName("Cysharp.AI.GenerateToonTabularArrayConverterAttribute",
1616
(node, cancellationToken) => true,
1717
(context, cancellationToken) =>
1818
{
@@ -29,7 +29,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
2929

3030
context.RegisterSourceOutput(tabularArray, EmitTabularArrayConverter!);
3131

32-
var simpleObject = context.SyntaxProvider.ForAttributeWithMetadataName("Cysharp.AI.GenerateToonSimpleObjectConverter",
32+
var simpleObject = context.SyntaxProvider.ForAttributeWithMetadataName("Cysharp.AI.GenerateToonSimpleObjectConverterAttribute",
3333
(node, cancellationToken) => true,
3434
(context, cancellationToken) =>
3535
{
@@ -47,9 +47,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
4747
context.RegisterSourceOutput(simpleObject, EmitSimpleObjectConverter!);
4848
}
4949

50-
static void EmitAttributes(IncrementalGeneratorPostInitializationContext context)
51-
{
52-
context.AddSource("GenerateToonTabularArrayConverter.g.cs", """
50+
public static readonly string GenerateToonTabularArrayConverterAttributeDefinition = """
5351
// <auto-generated/>
5452
#pragma warning disable
5553
#nullable enable
@@ -58,17 +56,25 @@ static void EmitAttributes(IncrementalGeneratorPostInitializationContext context
5856
5957
namespace Cysharp.AI
6058
{
59+
[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
6160
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
62-
internal sealed class GenerateToonTabularArrayConverter : Attribute
61+
internal sealed class GenerateToonTabularArrayConverterAttribute : Attribute
6362
{
6463
}
6564
65+
[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
6666
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
67-
internal sealed class GenerateToonSimpleObjectConverter : Attribute
67+
internal sealed class GenerateToonSimpleObjectConverterAttribute : Attribute
6868
{
6969
}
7070
}
71-
""".ReplaceLineEndings());
71+
""".ReplaceLineEndings();
72+
73+
static void EmitAttributes(IncrementalGeneratorPostInitializationContext context)
74+
{
75+
context.AddEmbeddedAttributeDefinition();
76+
77+
context.AddSource("GenerateToonTabularArrayConverter.g.cs", GenerateToonTabularArrayConverterAttributeDefinition);
7278
}
7379

7480
static void EmitTabularArrayConverter(SourceProductionContext sourceProductionContext, ToonObjectInfo objectInfo)
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
using System.Collections.Immutable;
5+
using System.Diagnostics.CodeAnalysis;
6+
using System.Runtime.CompilerServices;
7+
8+
namespace ToonEncoder.Tests;
9+
10+
#region Helper for Source Generator Testing
11+
12+
public static class CSharpGeneratorRunner
13+
{
14+
static Compilation baseCompilation = default!;
15+
16+
[ModuleInitializer]
17+
public static void InitializeCompilation()
18+
{
19+
var globalUsings = """
20+
global using System;
21+
global using Cysharp.AI;
22+
""";
23+
24+
var references = AppDomain.CurrentDomain.GetAssemblies()
25+
.Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location))
26+
.Select(x => MetadataReference.CreateFromFile(x.Location));
27+
//.Concat([
28+
// MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), // System.Console.dll
29+
// MetadataReference.CreateFromFile(typeof(IServiceProvider).Assembly.Location), // System.ComponentModel.dll
30+
// MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RequiredAttribute).Assembly.Location), // System.ComponentModel.DataAnnotations
31+
// MetadataReference.CreateFromFile(typeof(System.Text.Json.JsonDocument).Assembly.Location), // System.Text.Json.dll
32+
//]);
33+
34+
var compilation = CSharpCompilation.Create("generatortest",
35+
references: references,
36+
syntaxTrees: [CSharpSyntaxTree.ParseText(globalUsings, path: "GlobalUsings.cs")],
37+
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication, allowUnsafe: true)); // .exe
38+
39+
baseCompilation = compilation;
40+
}
41+
42+
public static (Compilation, ImmutableArray<Diagnostic>) RunGenerator([StringSyntax("C#-test")] string source, string[]? preprocessorSymbols = null, AnalyzerConfigOptionsProvider? options = null)
43+
{
44+
if (preprocessorSymbols == null)
45+
{
46+
preprocessorSymbols = new[] { "NET10_0_OR_GREATER" };
47+
}
48+
var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp14, preprocessorSymbols: preprocessorSymbols); // C# 14
49+
50+
var driver = CSharpGeneratorDriver.Create(new Cysharp.AI.ToonEncoderGenerator()).WithUpdatedParseOptions(parseOptions);
51+
if (options != null)
52+
{
53+
driver = (Microsoft.CodeAnalysis.CSharp.CSharpGeneratorDriver)driver.WithUpdatedAnalyzerConfigOptions(options);
54+
}
55+
56+
var compilation = baseCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(source, parseOptions));
57+
58+
driver.RunGeneratorsAndUpdateCompilation(compilation, out var newCompilation, out var diagnostics);
59+
return (newCompilation, diagnostics);
60+
}
61+
}
62+
63+
public class VerifyHelper(string idPrefix)
64+
{
65+
public async Task Ok([StringSyntax("C#-test")] string code, [CallerArgumentExpression("code")] string? codeExpr = null)
66+
{
67+
Console.WriteLine(codeExpr!);
68+
69+
var (compilation, diagnostics) = CSharpGeneratorRunner.RunGenerator(code);
70+
foreach (var item in diagnostics)
71+
{
72+
Console.WriteLine(item.ToString());
73+
}
74+
OutputGeneratedCode(compilation);
75+
76+
await Assert.That(diagnostics.Length).IsZero();
77+
}
78+
79+
public async Task Verify(int id, [StringSyntax("C#-test")] string code, string diagnosticsCodeSpan, [CallerArgumentExpression("code")] string? codeExpr = null)
80+
{
81+
Console.WriteLine(codeExpr!);
82+
83+
var (compilation, diagnostics) = CSharpGeneratorRunner.RunGenerator(code);
84+
foreach (var item in diagnostics)
85+
{
86+
Console.WriteLine(item.ToString());
87+
}
88+
OutputGeneratedCode(compilation);
89+
90+
await Assert.That(diagnostics.Length).IsEqualTo(1);
91+
await Assert.That(diagnostics[0].Id).IsEqualTo(idPrefix + id.ToString("000"));
92+
93+
var text = GetLocationText(diagnostics[0], compilation.SyntaxTrees);
94+
await Assert.That(text).IsEqualTo(diagnosticsCodeSpan);
95+
}
96+
97+
public (string, string)[] Verify([StringSyntax("C#-test")] string code, [CallerArgumentExpression("code")] string? codeExpr = null)
98+
{
99+
Console.WriteLine(codeExpr!);
100+
101+
var (compilation, diagnostics) = CSharpGeneratorRunner.RunGenerator(code);
102+
OutputGeneratedCode(compilation);
103+
return diagnostics.Select(x => (x.Id, GetLocationText(x, compilation.SyntaxTrees))).ToArray();
104+
}
105+
106+
string GetLocationText(Diagnostic diagnostic, IEnumerable<SyntaxTree> syntaxTrees)
107+
{
108+
var location = diagnostic.Location;
109+
110+
var textSpan = location.SourceSpan;
111+
var sourceTree = location.SourceTree;
112+
if (sourceTree == null)
113+
{
114+
var lineSpan = location.GetLineSpan();
115+
if (lineSpan.Path == null) return "";
116+
117+
sourceTree = syntaxTrees.FirstOrDefault(x => x.FilePath == lineSpan.Path);
118+
if (sourceTree == null) return "";
119+
}
120+
121+
var text = sourceTree.GetText().GetSubText(textSpan).ToString();
122+
return text;
123+
}
124+
125+
void OutputGeneratedCode(Compilation compilation)
126+
{
127+
foreach (var syntaxTree in compilation.SyntaxTrees)
128+
{
129+
if (!syntaxTree.FilePath.Contains("g.cs")) continue;
130+
Console.WriteLine(syntaxTree.ToString());
131+
}
132+
}
133+
}
134+
135+
#endregion
136+
137+
public class GeneratorTest
138+
{
139+
VerifyHelper verifier = new VerifyHelper("TEG");
140+
141+
[Test]
142+
public async Task TabularArrayGenerator()
143+
{
144+
await verifier.Ok("""
145+
[GenerateToonTabularArrayConverter]
146+
public record User(int Id, string Name, string Role);
147+
""");
148+
149+
await verifier.Verify(1, """
150+
[GenerateToonTabularArrayConverter]
151+
public record User(int Id, string Name, string Role, MyClass ng);
152+
153+
public class MyClass { }
154+
""", "User");
155+
}
156+
157+
[Test]
158+
public async Task SimpleObjectGenerator()
159+
{
160+
await verifier.Ok("""
161+
[GenerateToonSimpleObjectConverter]
162+
public class SimpleClass
163+
{
164+
public int Id { get; set; }
165+
public string? Name { get; set; }
166+
public MyEnum Me { get; set; }
167+
public int[]? MyProperty { get; set; }
168+
public User[]? MyUser { get; set; }
169+
}
170+
171+
public record User(int Id, string Name, string Role);
172+
173+
public enum MyEnum
174+
{
175+
Fruit, Orange, Apple
176+
}
177+
""");
178+
179+
await verifier.Verify(2, """
180+
[GenerateToonSimpleObjectConverter]
181+
public class SimpleClass
182+
{
183+
public int Id { get; set; }
184+
public string? Name { get; set; }
185+
public MyEnum Me { get; set; }
186+
public User2 U2 { get; set; }
187+
public int[]? MyProperty { get; set; }
188+
public User[]? MyUser { get; set; }
189+
}
190+
191+
public record User(int Id, string Name, string Role);
192+
193+
public class User2() { }
194+
195+
public enum MyEnum
196+
{
197+
Fruit, Orange, Apple
198+
}
199+
""", "SimpleClass");
200+
201+
202+
203+
}
204+
}
Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<PropertyGroup>
4-
<OutputType>Exe</OutputType>
5-
<TargetFramework>net10.0</TargetFramework>
6-
<ImplicitUsings>enable</ImplicitUsings>
7-
<Nullable>enable</Nullable>
8-
</PropertyGroup>
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
99

10-
<ItemGroup>
11-
<PackageReference Include="TUnit" Version="1.5.6" />
12-
</ItemGroup>
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" />
12+
<PackageReference Include="TUnit" Version="1.6.25" />
13+
</ItemGroup>
1314

14-
<ItemGroup>
15-
<ProjectReference Include="..\..\src\ToonEncoder\ToonEncoder.csproj" />
16-
</ItemGroup>
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\src\ToonEncoder\ToonEncoder.csproj" />
17+
<ProjectReference Include="..\..\src\ToonEncoder.Generator\ToonEncoder.Generator.csproj" />
18+
</ItemGroup>
1719

18-
<ItemGroup>
19-
<None Update="fixtures\decode\*.json">
20-
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
21-
</None>
22-
<None Update="fixtures\encode\*.json">
23-
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
24-
</None>
25-
</ItemGroup>
20+
<ItemGroup>
21+
<None Update="fixtures\decode\*.json">
22+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
23+
</None>
24+
<None Update="fixtures\encode\*.json">
25+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
26+
</None>
27+
</ItemGroup>
2628

2729
</Project>
File renamed without changes.

0 commit comments

Comments
 (0)