Skip to content

Commit b5dc97c

Browse files
committed
Split MixKhronosData.Rewriter into two phases
1 parent 565810e commit b5dc97c

File tree

2 files changed

+55
-25
lines changed

2 files changed

+55
-25
lines changed

.silktouch/ce8a69a66cd3bd3f.stout

0 Bytes
Binary file not shown.

sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -301,18 +301,20 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default)
301301
{
302302
var jobData = Jobs[ctx.JobKey];
303303
var proj = ctx.SourceProject;
304-
var rewriter = new Rewriter(jobData, logger);
304+
305+
// Rewrite phase 1
306+
var rewriter1 = new EnumRewriterPhase1(jobData, logger);
305307
foreach (var docId in proj?.DocumentIds ?? [])
306308
{
307-
var doc =
308-
proj!.GetDocument(docId) ?? throw new InvalidOperationException("Document missing");
309+
var doc = proj!.GetDocument(docId) ?? throw new InvalidOperationException("Document missing");
309310
proj = doc.WithSyntaxRoot(
310-
rewriter.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace()
311+
rewriter1.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace()
311312
?? throw new InvalidOperationException("Visit returned null.")
312313
).Project;
313314
}
314315

315-
foreach (var (filePath, node) in rewriter.GetNewSyntaxTrees())
316+
// Add missing enum types
317+
foreach (var (filePath, node) in rewriter1.GetMissingEnums())
316318
{
317319
proj = proj
318320
?.AddDocument(
@@ -323,6 +325,17 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default)
323325
.Project;
324326
}
325327

328+
// Rewrite phase 2
329+
var rewriter2 = new EnumRewriterPhase2(jobData);
330+
foreach (var docId in proj?.DocumentIds ?? [])
331+
{
332+
var doc = proj!.GetDocument(docId) ?? throw new InvalidOperationException("Document missing");
333+
proj = doc.WithSyntaxRoot(
334+
rewriter2.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace()
335+
?? throw new InvalidOperationException("Visit returned null.")
336+
).Project;
337+
}
338+
326339
ctx.SourceProject = proj;
327340
}
328341

@@ -1673,11 +1686,19 @@ jobKey is null
16731686
)]
16741687
private static partial Regex EndingsNotToTrim();
16751688

1676-
private class Rewriter(JobData job, ILogger logger) : CSharpSyntaxRewriter(true)
1689+
/// <summary>
1690+
/// Extracts enum constants that are defined as fields and moves them to their actual enum types.
1691+
/// Begins renaming FlagBits enums to Flags.
1692+
/// </summary>
1693+
/// <remarks>
1694+
/// This rewriter is split into two phases because NamespaceFromSyntaxNode breaks due to
1695+
/// the FieldDeclarationSyntax being modified.
1696+
/// </remarks>
1697+
private class EnumRewriterPhase1(JobData job, ILogger logger) : CSharpSyntaxRewriter
16771698
{
16781699
public HashSet<string> AlreadyPresentGroups { get; } = [];
16791700

1680-
public IEnumerable<(string FilePath, SyntaxNode Node)> GetNewSyntaxTrees()
1701+
public IEnumerable<(string FilePath, SyntaxNode Node)> GetMissingEnums()
16811702
{
16821703
var results = new List<(string FilePath, SyntaxNode Node)>();
16831704

@@ -1786,40 +1807,26 @@ private class Rewriter(JobData job, ILogger logger) : CSharpSyntaxRewriter(true)
17861807
}
17871808
}
17881809

1789-
// Rewrite syntax trees
1790-
// This is to ensure that these trees are processed similarly to all other trees in the project
1791-
results = results.Select(r => (r.FilePath, Visit(r.Node))).ToList();
1792-
17931810
return results;
17941811
}
17951812

17961813
public override SyntaxNode? VisitClassDeclaration(ClassDeclarationSyntax node)
17971814
{
1815+
// Remove empty classes
17981816
var ret = base.VisitClassDeclaration(node);
17991817
return ret is ClassDeclarationSyntax { Members.Count: 0 } ? null : ret;
18001818
}
18011819

18021820
public override SyntaxNode? VisitEnumDeclaration(EnumDeclarationSyntax node)
18031821
{
1822+
// Track which enums already exist
18041823
var identifier = node.Identifier.ToString();
18051824
identifier = identifier.Replace("FlagBits", "Flags");
18061825

1807-
if (
1808-
job.Groups.TryGetValue(identifier, out var group)
1809-
&& !node.Ancestors().OfType<BaseTypeDeclarationSyntax>().Any()
1810-
)
1826+
if (job.Groups.TryGetValue(identifier, out var group)
1827+
&& !node.Ancestors().OfType<BaseTypeDeclarationSyntax>().Any())
18111828
{
18121829
AlreadyPresentGroups.Add(identifier);
1813-
1814-
if (group.KnownBitmask)
1815-
{
1816-
// Add [Flags] attribute
1817-
var flagsAttribute = AttributeList(
1818-
SingletonSeparatedList(
1819-
Attribute(IdentifierName("Flags"))));
1820-
1821-
node = node.WithAttributeLists(node.AttributeLists.Add(flagsAttribute));
1822-
}
18231830
}
18241831

18251832
return base.VisitEnumDeclaration(node.WithIdentifier(Identifier(identifier)));
@@ -1894,6 +1901,29 @@ private class Rewriter(JobData job, ILogger logger) : CSharpSyntaxRewriter(true)
18941901

18951902
return base.VisitFieldDeclaration(node);
18961903
}
1904+
}
1905+
1906+
/// <summary>
1907+
/// Finishes renaming FlagBits enums to Flags.
1908+
/// Marks bitmask enums with the [Flags] attribute.
1909+
/// </summary>
1910+
private class EnumRewriterPhase2(JobData job) : CSharpSyntaxRewriter(true)
1911+
{
1912+
public override SyntaxNode? VisitEnumDeclaration(EnumDeclarationSyntax node)
1913+
{
1914+
var identifier = node.Identifier.ToString();
1915+
if (job.Groups.TryGetValue(identifier, out var group) && group.KnownBitmask)
1916+
{
1917+
// Add [Flags] attribute
1918+
var flagsAttribute = AttributeList(
1919+
SingletonSeparatedList(
1920+
Attribute(IdentifierName("Flags"))));
1921+
1922+
node = node.WithAttributeLists(node.AttributeLists.Add(flagsAttribute));
1923+
}
1924+
1925+
return base.VisitEnumDeclaration(node);
1926+
}
18971927

18981928
public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node) => IdentifierName(node.Identifier.ToString().Replace("FlagBits", "Flags"));
18991929
}

0 commit comments

Comments
 (0)