From 7938a0cbb3a52005a361de0e338098f18babeb42 Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 13 Apr 2026 20:07:36 -0400 Subject: [PATCH 01/25] Update ClangSharp.PInvokeGenerator --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 0c0cf4d13b..385845b466 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -21,7 +21,7 @@ - + From 78b8ec4a6ace41b3331ebca8fda05d8f4e599829 Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 13 Apr 2026 21:48:16 -0400 Subject: [PATCH 02/25] Update comment on ModifyAllReferencesAsync in TransformHandles --- sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs index 04feaa8cd0..722f1a3b94 100644 --- a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs +++ b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs @@ -86,8 +86,8 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = } } - // Do the two following transformation to all references of the handle types: - // 2. Reduce pointer dimensions + // Reduce pointer dimensions + // The -Handle suffix will be applied later by PrettifyNames if the user configures it to do so ctx.SourceProject = project; await LocationTransformationUtils.ModifyAllReferencesAsync( ctx, From a11ef49ae9ee31e49c560d0d1090c1bfbd1d24c0 Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 13 Apr 2026 23:32:04 -0400 Subject: [PATCH 03/25] Format files using CSharpier These were written before I installed the CSharpier plugin so they were not formatted. --- .../IdentifierRenamingTransformer.cs | 23 ++++++--- .../LocationTransformationRewriter.cs | 19 +++++-- .../LocationTransformationUtils.cs | 51 ++++++++++++------- .../LocationTransformer.cs | 5 +- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/IdentifierRenamingTransformer.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/IdentifierRenamingTransformer.cs index 3dcd4a281a..d2d459e11b 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/IdentifierRenamingTransformer.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/IdentifierRenamingTransformer.cs @@ -14,19 +14,25 @@ public class IdentifierRenamingTransformer : LocationTransformer { private ISymbol symbol = null!; - private readonly IReadOnlyDictionary> newNameLookup; + private readonly IReadOnlyDictionary< + string, + List<(ISymbol Symbol, string NewName)> + > newNameLookup; /// /// Creates a new IdentifierRenamingTransformer. /// /// The new names for each symbol - public IdentifierRenamingTransformer(IEnumerable<(ISymbol Symbol, string NewName)> newNames) : this(CreateNameLookup(newNames)) {} + public IdentifierRenamingTransformer(IEnumerable<(ISymbol Symbol, string NewName)> newNames) + : this(CreateNameLookup(newNames)) { } /// /// Creates a new IdentifierRenamingTransformer. /// /// The new names for each symbol grouped by symbol name. - public IdentifierRenamingTransformer(IReadOnlyDictionary> newNameLookup) + public IdentifierRenamingTransformer( + IReadOnlyDictionary> newNameLookup + ) { this.newNameLookup = newNameLookup; } @@ -34,9 +40,14 @@ public IdentifierRenamingTransformer(IReadOnlyDictionary /// Creates a name lookup dictionary designed for . /// - public static IReadOnlyDictionary> CreateNameLookup(IEnumerable<(ISymbol Symbol, string NewName)> names) + public static IReadOnlyDictionary< + string, + List<(ISymbol Symbol, string NewName)> + > CreateNameLookup(IEnumerable<(ISymbol Symbol, string NewName)> names) { - return names.GroupBy(t => t.Symbol.Name).ToDictionary(group => group.Key, group => group.ToList()); + return names + .GroupBy(t => t.Symbol.Name) + .ToDictionary(group => group.Key, group => group.ToList()); } /// @@ -68,7 +79,7 @@ private SyntaxToken GetRenamed(ISymbol symbol, SyntaxToken currentNameIdentifier return currentNameIdentifier; } - // ----- Types ----- + // ----- Types ----- /// public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index 47f48c8014..a5ae9006c6 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -18,7 +18,10 @@ namespace Silk.NET.SilkTouch.Mods.LocationTransformation; /// /// Symbols to search for. /// Transformers to use on each found symbol reference. -public class LocationTransformationRewriter(HashSet symbols, List transformers) : CSharpSyntaxRewriter +public class LocationTransformationRewriter( + HashSet symbols, + List transformers +) : CSharpSyntaxRewriter { // Symbols can also be referenced within XML doc, which are trivia nodes. /// @@ -66,7 +69,8 @@ public void Initialize(SemanticModel semanticModel) { // Apply deferred transformer var deferredTransformer = transformers[transformation.TransformerIndex]; - modifiedNode = deferredTransformer.Visit(modifiedNode) + modifiedNode = deferredTransformer + .Visit(modifiedNode) .WithLeadingTrivia(unmodifiedNode.GetLeadingTrivia().Select(VisitTrivia)) .WithTrailingTrivia(unmodifiedNode.GetTrailingTrivia()); } @@ -105,13 +109,17 @@ public void Initialize(SemanticModel semanticModel) { // We can't directly transform the node since we are at the wrong place in the hierarchy // Defer it so it is processed later - queuedTransformations.Add(selectedNode, new QueuedTransformation(transformation.Symbol, i)); + queuedTransformations.Add( + selectedNode, + new QueuedTransformation(transformation.Symbol, i) + ); break; } // Transform the node - modifiedNode = transformer.Visit(modifiedNode) + modifiedNode = transformer + .Visit(modifiedNode) .WithLeadingTrivia(unmodifiedNode.GetLeadingTrivia().Select(VisitTrivia)) .WithTrailingTrivia(unmodifiedNode.GetTrailingTrivia()); } @@ -247,7 +255,8 @@ public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSynta /// public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { - var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetTypeInfo(node).Type; + var symbol = + semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetTypeInfo(node).Type; ReportSymbol(node, symbol); return base.VisitIdentifierName(node)!; diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs index 8ae9303d72..025c282b38 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs @@ -26,7 +26,8 @@ public static async Task ModifyAllReferencesAsync( IEnumerable symbols, IEnumerable transformers, ILogger? logger = null, - CancellationToken ct = default) + CancellationToken ct = default + ) { var sourceProject = ctx.SourceProject; if (sourceProject == null) @@ -37,33 +38,45 @@ public static async Task ModifyAllReferencesAsync( // We need to track both the original solution and modified solution // The original is where we retrieve documents and semantic models // The modified solution is where we place the results - IReadOnlyList documentIds = [.. sourceProject.DocumentIds, .. ctx.TestProject?.DocumentIds ?? []]; + IReadOnlyList documentIds = + [ + .. sourceProject.DocumentIds, + .. ctx.TestProject?.DocumentIds ?? [], + ]; var originalSolution = sourceProject.Solution; var newDocuments = new ConcurrentDictionary(); var symbolSet = new HashSet(symbols, SymbolEqualityComparer.Default); - await Parallel.ForEachAsync(documentIds, ct, async (documentId, _) => { - var originalDocument = originalSolution.GetDocument(documentId); - if (originalDocument == null) + await Parallel.ForEachAsync( + documentIds, + ct, + async (documentId, _) => { - return; - } + var originalDocument = originalSolution.GetDocument(documentId); + if (originalDocument == null) + { + return; + } - var originalRoot = await originalDocument.GetSyntaxRootAsync(ct); - var semanticModel = await originalDocument.GetSemanticModelAsync(ct); + var originalRoot = await originalDocument.GetSyntaxRootAsync(ct); + var semanticModel = await originalDocument.GetSemanticModelAsync(ct); - if (originalRoot == null || semanticModel == null) - { - return; - } + if (originalRoot == null || semanticModel == null) + { + return; + } - // Since this is multithreaded, each thread needs their own copy of the rewriter and transformers - var rewriter = new LocationTransformationRewriter(symbolSet, [..transformers.Select(t => t.GetThreadSafeCopy())]); - rewriter.Initialize(semanticModel); + // Since this is multithreaded, each thread needs their own copy of the rewriter and transformers + var rewriter = new LocationTransformationRewriter( + symbolSet, + [.. transformers.Select(t => t.GetThreadSafeCopy())] + ); - var newRoot = rewriter.Visit(originalRoot); - newDocuments.TryAdd(documentId, newRoot); - }); + rewriter.Initialize(semanticModel); + var newRoot = rewriter.Visit(originalRoot); + newDocuments.TryAdd(documentId, newRoot); + } + ); var modifiedSolution = sourceProject.Solution; foreach (var (documentId, newRoot) in newDocuments) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs index 56c9884937..fa647abd8d 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs @@ -24,7 +24,10 @@ public abstract class LocationTransformer : CSharpSyntaxRewriter /// The node hierarchy as a reversed stack. Index 0 is the current node. Index 1 is its parent and so on. /// The symbol that is associated with this node. /// The given node, another node, or null. - public abstract SyntaxNode? GetNodeToModify(IReadOnlyList hierarchy, ISymbol symbol); + public abstract SyntaxNode? GetNodeToModify( + IReadOnlyList hierarchy, + ISymbol symbol + ); /// /// Clone this location transformer for purposes of thread safety. From 9cf0637d92da248814f0ba1aa9b4cc319580e8ef Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 13 Apr 2026 23:56:52 -0400 Subject: [PATCH 04/25] Remove GetTypeInfo call GetTypeInfo should be unnecessary since it gets the type of an expression. For non-type expressions (eg: `5` is an int), this isn't useful for us. This is arguably an indirect reference to int, but the current Silk generator only cares about modifying direct references. For type expressions (eg: `int` refers to int), GetSymbolInfo will also return the same symbol. --- .../LocationTransformation/LocationTransformationRewriter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index a5ae9006c6..a19e065d33 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -255,8 +255,7 @@ public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSynta /// public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { - var symbol = - semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetTypeInfo(node).Type; + var symbol = semanticModel.GetSymbolInfo(node).Symbol; ReportSymbol(node, symbol); return base.VisitIdentifierName(node)!; From 8c05ec7270578797c1fd3c5c3b64b094e74e4abc Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 00:13:16 -0400 Subject: [PATCH 05/25] Get the compilation once* *Roslyn already caches this internally. This is mainly for avoiding the async method call. Difference is probably not measurable, but theoretically this is faster. --- .../LocationTransformationUtils.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs index 025c282b38..745230ea4f 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs @@ -45,6 +45,12 @@ public static async Task ModifyAllReferencesAsync( ]; var originalSolution = sourceProject.Solution; + var compilation = await sourceProject.GetCompilationAsync(ct); + if (compilation == null) + { + return; + } + var newDocuments = new ConcurrentDictionary(); var symbolSet = new HashSet(symbols, SymbolEqualityComparer.Default); await Parallel.ForEachAsync( @@ -59,13 +65,13 @@ await Parallel.ForEachAsync( } var originalRoot = await originalDocument.GetSyntaxRootAsync(ct); - var semanticModel = await originalDocument.GetSemanticModelAsync(ct); - - if (originalRoot == null || semanticModel == null) + if (originalRoot == null) { return; } + var semanticModel = compilation.GetSemanticModel(originalRoot.SyntaxTree); + // Since this is multithreaded, each thread needs their own copy of the rewriter and transformers var rewriter = new LocationTransformationRewriter( symbolSet, From fe50783b8cdd1de953dc415d5d6b3fe8283d2b8b Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 00:19:49 -0400 Subject: [PATCH 06/25] Compare against _relevantIdentifiers set before calling GetSymbolInfo --- .../LocationTransformationRewriter.cs | 85 +++++++++++-------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index a19e065d33..22dbfaffc0 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -14,39 +14,47 @@ namespace Silk.NET.SilkTouch.Mods.LocationTransformation; /// and modifies the nodes only when coming back up. ///
/// Modifying nodes cause them to be detached from the semantic model (meaning no symbol information), -/// so this ensures that we gather all of the data we need before making changes. +/// so this ensures that we gather all the data we need before making changes. /// -/// Symbols to search for. -/// Transformers to use on each found symbol reference. -public class LocationTransformationRewriter( - HashSet symbols, - List transformers -) : CSharpSyntaxRewriter +public class LocationTransformationRewriter : CSharpSyntaxRewriter { // Symbols can also be referenced within XML doc, which are trivia nodes. /// public override bool VisitIntoStructuredTrivia => true; - private readonly Dictionary queuedTransformations = new(); + private readonly Dictionary _queuedTransformations = new(); /// The symbol for the node. /// The index of the transformer that should be used when continuing the transformation process. private record struct QueuedTransformation(ISymbol Symbol, int TransformerIndex); - private readonly List tempNodeList = new(); + private readonly List _tempNodeList = new(); /// /// The semantic model of the currently processed document. /// - private SemanticModel semanticModel = null!; + private SemanticModel _semanticModel = null!; + + private readonly HashSet _symbols; + private readonly List _transformers; + private readonly HashSet _relevantIdentifiers; + + /// Symbols to search for. + /// Transformers to use on each found symbol reference. + public LocationTransformationRewriter( + HashSet symbols, + List transformers + ) + { + _symbols = symbols; + _transformers = transformers; + _relevantIdentifiers = _symbols.Select(s => s.Name).ToHashSet(); + } /// /// Initializes the renamer to work for a new document. Must be called before visiting any nodes. /// - public void Initialize(SemanticModel semanticModel) - { - this.semanticModel = semanticModel; - } + public void Initialize(SemanticModel semanticModel) => _semanticModel = semanticModel; /// [return: NotNullIfNotNull("unmodifiedNode")] @@ -63,12 +71,12 @@ public void Initialize(SemanticModel semanticModel) // Check for queued transformation // To apply a transformation, we must be in the same level in the hierarchy as the selected node // We also must apply transformations when going back up in the hierarchy so we don't overwrite previous transformations - if (queuedTransformations.Remove(unmodifiedNode, out var transformation)) + if (_queuedTransformations.Remove(unmodifiedNode, out var transformation)) { if (transformation.TransformerIndex >= 0) { // Apply deferred transformer - var deferredTransformer = transformers[transformation.TransformerIndex]; + var deferredTransformer = _transformers[transformation.TransformerIndex]; modifiedNode = deferredTransformer .Visit(modifiedNode) .WithLeadingTrivia(unmodifiedNode.GetLeadingTrivia().Select(VisitTrivia)) @@ -76,12 +84,12 @@ public void Initialize(SemanticModel semanticModel) } // Continue applying remaining transformers - for (var i = transformation.TransformerIndex + 1; i < transformers.Count; i++) + for (var i = transformation.TransformerIndex + 1; i < _transformers.Count; i++) { - var transformer = transformers[i]; + var transformer = _transformers[i]; // Calculate hierarchy - var hierarchy = tempNodeList; + var hierarchy = _tempNodeList; { hierarchy.Clear(); @@ -109,7 +117,7 @@ public void Initialize(SemanticModel semanticModel) { // We can't directly transform the node since we are at the wrong place in the hierarchy // Defer it so it is processed later - queuedTransformations.Add( + _queuedTransformations.Add( selectedNode, new QueuedTransformation(transformation.Symbol, i) ); @@ -130,12 +138,12 @@ public void Initialize(SemanticModel semanticModel) private void ReportSymbol(SyntaxNode node, ISymbol? symbol) { - if (symbol == null || !symbols.Contains(symbol)) + if (symbol == null || !_symbols.Contains(symbol)) { return; } - queuedTransformations.Add(node, new QueuedTransformation(symbol, -1)); + _queuedTransformations.Add(node, new QueuedTransformation(symbol, -1)); } // ----- Types ----- @@ -143,7 +151,7 @@ private void ReportSymbol(SyntaxNode node, ISymbol? symbol) /// public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitClassDeclaration(node)!; @@ -152,7 +160,7 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) /// public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitStructDeclaration(node)!; @@ -161,7 +169,7 @@ public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) /// public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitInterfaceDeclaration(node)!; @@ -170,7 +178,7 @@ public override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax /// public override SyntaxNode VisitRecordDeclaration(RecordDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitRecordDeclaration(node)!; @@ -179,7 +187,7 @@ public override SyntaxNode VisitRecordDeclaration(RecordDeclarationSyntax node) /// public override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitDelegateDeclaration(node)!; @@ -188,7 +196,7 @@ public override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax no /// public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitEnumDeclaration(node)!; @@ -199,7 +207,7 @@ public override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node) /// public override SyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitEnumMemberDeclaration(node)!; @@ -208,7 +216,7 @@ public override SyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSynta /// public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitPropertyDeclaration(node)!; @@ -217,7 +225,7 @@ public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax no /// public override SyntaxNode VisitEventDeclaration(EventDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitEventDeclaration(node)!; @@ -226,7 +234,7 @@ public override SyntaxNode VisitEventDeclaration(EventDeclarationSyntax node) /// public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitMethodDeclaration(node)!; @@ -235,7 +243,7 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) /// public override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitConstructorDeclaration(node)!; @@ -244,7 +252,7 @@ public override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyn /// public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitDestructorDeclaration(node)!; @@ -255,7 +263,12 @@ public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSynta /// public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { - var symbol = semanticModel.GetSymbolInfo(node).Symbol; + if (!_relevantIdentifiers.Contains(node.Identifier.Text)) + { + return node; + } + + var symbol = _semanticModel.GetSymbolInfo(node).Symbol; ReportSymbol(node, symbol); return base.VisitIdentifierName(node)!; @@ -265,7 +278,7 @@ public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) /// public override SyntaxNode VisitVariableDeclarator(VariableDeclaratorSyntax node) { - var symbol = semanticModel.GetDeclaredSymbol(node); + var symbol = _semanticModel.GetDeclaredSymbol(node); ReportSymbol(node, symbol); return base.VisitVariableDeclarator(node)!; From 9cb75e1102a4051c786448d0e7cf97b46738a0ef Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 00:19:57 -0400 Subject: [PATCH 07/25] Skip using directives --- .../LocationTransformation/LocationTransformationRewriter.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index 22dbfaffc0..200eea8202 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -283,4 +283,9 @@ public override SyntaxNode VisitVariableDeclarator(VariableDeclaratorSyntax node return base.VisitVariableDeclarator(node)!; } + + // ----- Skipped nodes ----- + + /// + public override SyntaxNode VisitUsingDirective(UsingDirectiveSyntax node) => node; } From 56382211b52b83e958b228073a4ddcd2023c4339 Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 00:29:17 -0400 Subject: [PATCH 08/25] Add ProfilingScope --- .../SilkTouch/Profiling/ProfilingScope.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs diff --git a/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs b/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs new file mode 100644 index 0000000000..d7393a5afc --- /dev/null +++ b/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace Silk.NET.SilkTouch.Profiling; + +/// +/// Lightweight way to profile a section of code. +/// +internal readonly struct ProfilingScope : IDisposable +{ + private readonly string name; + private readonly long timestamp; + + public ProfilingScope(string name) + { + this.name = name; + timestamp = Stopwatch.GetTimestamp(); + } + + public void Dispose() + { + var elapsed = Stopwatch.GetElapsedTime(timestamp); + Console.WriteLine( + "Elapsed time for scope \"{0}\": {1:F3} ms", + name, + elapsed.TotalMilliseconds + ); + } +} From a0ea115d7dd1907ed3c1bf60f3751485596b2148 Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 00:45:47 -0400 Subject: [PATCH 09/25] Add comment on _relevantIdentifiers --- .../LocationTransformation/LocationTransformationRewriter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index 200eea8202..e0a921de92 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -48,6 +48,9 @@ List transformers { _symbols = symbols; _transformers = transformers; + + // Used to skip symbol lookups + // Does not handle the omission of the "-Attribute" suffix, but generally, we don't need to transform attributes _relevantIdentifiers = _symbols.Select(s => s.Name).ToHashSet(); } From ed941db1377cef64b6c00085dada8ad1d15a054e Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 14:33:30 -0400 Subject: [PATCH 10/25] Fix field naming convention in ProfilingScope --- .../SilkTouch/SilkTouch/Profiling/ProfilingScope.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs b/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs index d7393a5afc..03989bda03 100644 --- a/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs +++ b/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs @@ -10,21 +10,21 @@ namespace Silk.NET.SilkTouch.Profiling; ///
internal readonly struct ProfilingScope : IDisposable { - private readonly string name; - private readonly long timestamp; + private readonly string _name; + private readonly long _timestamp; public ProfilingScope(string name) { - this.name = name; - timestamp = Stopwatch.GetTimestamp(); + _name = name; + _timestamp = Stopwatch.GetTimestamp(); } public void Dispose() { - var elapsed = Stopwatch.GetElapsedTime(timestamp); + var elapsed = Stopwatch.GetElapsedTime(_timestamp); Console.WriteLine( "Elapsed time for scope \"{0}\": {1:F3} ms", - name, + _name, elapsed.TotalMilliseconds ); } From 8d5b978ec39d48223e50045e593e408edd4be614 Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 14:46:08 -0400 Subject: [PATCH 11/25] Optimize document renaming in PrettifyNames Conflict checking was O(n), now it is O(1). --- .../SilkTouch/SilkTouch/Mods/PrettifyNames.cs | 45 +++++++------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs index 100f43ad25..bcca591f5f 100644 --- a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs @@ -195,9 +195,15 @@ await proj.GetCompilationAsync(ct) // Change the filenames where appropriate. proj = ctx.SourceProject; + var typeNames = newNames.GetValueOrDefault("", []); var typeNamesLongestFirst = typeNames.OrderByDescending(x => x.Key.Length).ToArray(); + var documentPaths = proj + .Documents.Select(d => d.FilePath) + .Where(d => d != null) + .ToHashSet(); + foreach (var docId in proj.DocumentIds) { var doc = proj.GetDocument(docId); @@ -206,6 +212,7 @@ await proj.GetCompilationAsync(ct) continue; } + // Find best matching document for renamed types var firstMatch = typeNamesLongestFirst.FirstOrDefault(x => doc.FilePath.Contains(x.Key) || doc.Name.Contains(x.Key) ); @@ -214,43 +221,23 @@ await proj.GetCompilationAsync(ct) continue; } + // Rename doc and update path var originalName = doc.Name; + var originalPath = doc.FilePath; doc = doc.ReplaceNameAndPath(oldName, newName); - var found = false; - if (doc.FilePath is not null) - { - foreach (var checkDocId in proj.DocumentIds) - { - if (checkDocId == docId) - { - continue; - } - - var checkDoc = proj.GetDocument(checkDocId); - if (checkDoc?.FilePath is null) - { - continue; - } - - if (checkDoc.FilePath == doc.FilePath) - { - found = true; - break; - } - } - } - - if (found) + // Check for path conflict + documentPaths.Remove(originalPath); + if (!documentPaths.Add(doc.FilePath!)) { logger.LogError( $"{originalName} -> {doc.Name} failed to rename file as a file already exists at {doc.FilePath}" ); + + continue; } - else - { - proj = doc.Project; - } + + proj = doc.Project; } ctx.SourceProject = proj; From 878a90f1b5e456abb3999911ca0ac7edc20a5bb7 Mon Sep 17 00:00:00 2001 From: William Chen Date: Tue, 14 Apr 2026 14:58:56 -0400 Subject: [PATCH 12/25] Use normalized relative paths during conflict checking This is to prevent false negatives from mismatched path formats. --- sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs index bcca591f5f..da23b4a6dc 100644 --- a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs @@ -200,7 +200,7 @@ await proj.GetCompilationAsync(ct) var typeNamesLongestFirst = typeNames.OrderByDescending(x => x.Key.Length).ToArray(); var documentPaths = proj - .Documents.Select(d => d.FilePath) + .Documents.Select(d => d.RelativePath()) .Where(d => d != null) .ToHashSet(); @@ -223,12 +223,13 @@ await proj.GetCompilationAsync(ct) // Rename doc and update path var originalName = doc.Name; - var originalPath = doc.FilePath; + var originalPath = doc.RelativePath(); doc = doc.ReplaceNameAndPath(oldName, newName); + var newPath = doc.RelativePath(); // Check for path conflict documentPaths.Remove(originalPath); - if (!documentPaths.Add(doc.FilePath!)) + if (!documentPaths.Add(newPath)) { logger.LogError( $"{originalName} -> {doc.Name} failed to rename file as a file already exists at {doc.FilePath}" From 9d52a44d37d001e111305aae8e3b3ccd5a8a22c1 Mon Sep 17 00:00:00 2001 From: William Chen Date: Wed, 15 Apr 2026 15:32:53 -0400 Subject: [PATCH 13/25] Remove NormalizeWhitespace calls (much faster, but breaks generator) (cherry picked from commit 8cf1324438dfd909722fd7fe3cf63ded355c0b9b) --- .../SilkTouch/Mods/AddApiProfiles.cs | 4 +- .../SilkTouch/Mods/AddOpaqueStructs.cs | 12 +++--- .../SilkTouch/SilkTouch/Mods/AddVTables.cs | 9 +---- .../SilkTouch/Mods/BakeSourceSets.cs | 2 +- .../SilkTouch/Mods/ChangeNamespace.cs | 38 ++++++++++--------- .../SilkTouch/Mods/ExtractHandles.cs | 2 +- .../SilkTouch/Mods/ExtractNestedTyping.cs | 8 ++-- .../Mods/InterceptNativeFunctions.cs | 2 +- .../SilkTouch/Mods/MarkNativeNames.cs | 2 +- .../SilkTouch/Mods/MixKhronosData.cs | 8 ++-- .../SilkTouch/Mods/StripAttributes.cs | 2 +- .../SilkTouch/Mods/TransformEnums.cs | 2 +- .../SilkTouch/Mods/TransformFunctions.cs | 2 +- .../SilkTouch/Mods/TransformHandles.cs | 4 +- .../SilkTouch/Mods/TransformProperties.cs | 2 +- .../Transformation/FunctionTransformer.cs | 1 - 16 files changed, 44 insertions(+), 56 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/AddApiProfiles.cs b/sources/SilkTouch/SilkTouch/Mods/AddApiProfiles.cs index 947b06a6d2..0df1ec07ea 100644 --- a/sources/SilkTouch/SilkTouch/Mods/AddApiProfiles.cs +++ b/sources/SilkTouch/SilkTouch/Mods/AddApiProfiles.cs @@ -265,9 +265,7 @@ rewriter.Profile is null logger.LogDebug("No profile identified for {}", path); } - ctx.SourceProject = doc.WithSyntaxRoot( - rewriter.Visit(root).NormalizeWhitespace() - ).Project; + ctx.SourceProject = doc.WithSyntaxRoot(rewriter.Visit(root)).Project; rewriter.Profile = null; } } diff --git a/sources/SilkTouch/SilkTouch/Mods/AddOpaqueStructs.cs b/sources/SilkTouch/SilkTouch/Mods/AddOpaqueStructs.cs index 34d4e13355..5d8cafcb0e 100644 --- a/sources/SilkTouch/SilkTouch/Mods/AddOpaqueStructs.cs +++ b/sources/SilkTouch/SilkTouch/Mods/AddOpaqueStructs.cs @@ -72,11 +72,10 @@ public Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) { var qualified = name.LastIndexOf('.'); var ns = - qualified != -1 - ? ModUtils.NamespaceIntoIdentifierName(name.AsSpan()[..qualified]) - : _defaultNamespaces.TryGetValue(ctx.JobKey, out var def) - ? ModUtils.NamespaceIntoIdentifierName(def) - : null; + qualified != -1 ? ModUtils.NamespaceIntoIdentifierName(name.AsSpan()[..qualified]) + : _defaultNamespaces.TryGetValue(ctx.JobKey, out var def) + ? ModUtils.NamespaceIntoIdentifierName(def) + : null; if (ns is null) { logger.LogWarning( @@ -107,8 +106,7 @@ public Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) ) ) ) - ) - .NormalizeWhitespace(), + ), filePath: proj.FullPath(fname) ).Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/AddVTables.cs b/sources/SilkTouch/SilkTouch/Mods/AddVTables.cs index e3d3326dfd..c2fc2b5c99 100644 --- a/sources/SilkTouch/SilkTouch/Mods/AddVTables.cs +++ b/sources/SilkTouch/SilkTouch/Mods/AddVTables.cs @@ -1454,8 +1454,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) rw.Reset(); proj = doc.WithSyntaxRoot( - rw.Visit(node)?.NormalizeWhitespace() - ?? throw new InvalidOperationException("Visit returned null") + rw.Visit(node) ?? throw new InvalidOperationException("Visit returned null") ).Project; if (rw.InterfacePartials.Count == 0) { @@ -1515,11 +1514,7 @@ rw.ClassName is not null ) { proj = proj - ?.AddDocument( - Path.GetFileName(fname), - root.NormalizeWhitespace(), - filePath: proj.FullPath(fname) - ) + ?.AddDocument(Path.GetFileName(fname), root, filePath: proj.FullPath(fname)) .Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs b/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs index 16885d4a3a..36f5d61732 100644 --- a/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs +++ b/sources/SilkTouch/SilkTouch/Mods/BakeSourceSets.cs @@ -391,7 +391,7 @@ .. ctx { proj = proj.AddDocument( Path.GetFileName(bakedPath), - bakedRoot.NormalizeWhitespace(), + bakedRoot, // we can forgive the below nulls because RelativePath checks them, and returns null if they're null. filePath: proj.FullPath(bakedPath) ).Project; diff --git a/sources/SilkTouch/SilkTouch/Mods/ChangeNamespace.cs b/sources/SilkTouch/SilkTouch/Mods/ChangeNamespace.cs index 56edb5619f..ce19c5cca8 100644 --- a/sources/SilkTouch/SilkTouch/Mods/ChangeNamespace.cs +++ b/sources/SilkTouch/SilkTouch/Mods/ChangeNamespace.cs @@ -59,7 +59,8 @@ public Task> BeforeScrapeAsync(string key, List rsps[i] = rsp with { - GeneratorConfiguration = rsp.GeneratorConfiguration.ToWrapper() with { + GeneratorConfiguration = rsp.GeneratorConfiguration.ToWrapper() with + { DefaultNamespace = def, WithNamespaces = with, }, @@ -91,7 +92,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj!.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } @@ -116,17 +117,16 @@ public Rewriter( _usingsToAdd.Clear(); return base.VisitCompilationUnit(node) switch { - CompilationUnitSyntax syntax - => syntax.AddUsings( - _usingsToAdd - .Select(x => UsingDirective(ModUtils.NamespaceIntoIdentifierName(x))) - .Where(x => - syntax.Usings.All(y => x.Name?.ToString() != y.Name?.ToString()) - ) - .ToArray() - ), + CompilationUnitSyntax syntax => syntax.AddUsings( + _usingsToAdd + .Select(x => UsingDirective(ModUtils.NamespaceIntoIdentifierName(x))) + .Where(x => + syntax.Usings.All(y => x.Name?.ToString() != y.Name?.ToString()) + ) + .ToArray() + ), { } ret => ret, - null => null + null => null, }; } @@ -140,10 +140,11 @@ CompilationUnitSyntax syntax } return base.VisitNamespaceDeclaration(node) switch { - NamespaceDeclarationSyntax syntax - => syntax.WithName(ModUtils.NamespaceIntoIdentifierName(newNs)), + NamespaceDeclarationSyntax syntax => syntax.WithName( + ModUtils.NamespaceIntoIdentifierName(newNs) + ), { } ret => ret, - null => null + null => null, }; } @@ -159,10 +160,11 @@ FileScopedNamespaceDeclarationSyntax node } return base.VisitFileScopedNamespaceDeclaration(node) switch { - FileScopedNamespaceDeclarationSyntax syntax - => syntax.WithName(ModUtils.NamespaceIntoIdentifierName(newNs)), + FileScopedNamespaceDeclarationSyntax syntax => syntax.WithName( + ModUtils.NamespaceIntoIdentifierName(newNs) + ), { } ret => ret, - null => null + null => null, }; } } diff --git a/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs b/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs index d1018b9caf..f38e321042 100644 --- a/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs +++ b/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs @@ -51,7 +51,7 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = project = project .AddDocument( Path.GetFileName(relativePath), - node.NormalizeWhitespace(), + node, filePath: project.FullPath(relativePath) ) .Project; diff --git a/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs b/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs index e5073907e0..4d5ff5fb28 100644 --- a/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs +++ b/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs @@ -86,7 +86,7 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = // This is also where extracted enums are processed. rewriter.File = fname; project = doc.WithSyntaxRoot( - rewriter.Visit(node)?.NormalizeWhitespace() + rewriter.Visit(node) ?? throw new InvalidOperationException("Rewriter returned null") ).Project; @@ -110,8 +110,7 @@ rewriter.Namespace is not null ) ) : SingletonList(newStruct) - ) - .NormalizeWhitespace(), + ), filePath: project.FullPath( $"{fname.AsSpan()[..fname.LastIndexOf('/')]}/{newStruct.Identifier}.gen.cs" ) @@ -174,8 +173,7 @@ rewriter.Namespace is not null .WithMembers(SingletonList(typeDecl)) ) : SingletonList(typeDecl) - ) - .NormalizeWhitespace(), + ), filePath: project.FullPath($"{dir}/{identifier}.gen.cs") ) .Project; diff --git a/sources/SilkTouch/SilkTouch/Mods/InterceptNativeFunctions.cs b/sources/SilkTouch/SilkTouch/Mods/InterceptNativeFunctions.cs index cb563d3bf5..0c36df137a 100644 --- a/sources/SilkTouch/SilkTouch/Mods/InterceptNativeFunctions.cs +++ b/sources/SilkTouch/SilkTouch/Mods/InterceptNativeFunctions.cs @@ -48,7 +48,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj!.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/MarkNativeNames.cs b/sources/SilkTouch/SilkTouch/Mods/MarkNativeNames.cs index ebf68b4b0e..9f8aa554d1 100644 --- a/sources/SilkTouch/SilkTouch/Mods/MarkNativeNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/MarkNativeNames.cs @@ -37,7 +37,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs b/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs index 98395e7517..5a48a038a4 100644 --- a/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs +++ b/sources/SilkTouch/SilkTouch/Mods/MixKhronosData.cs @@ -363,7 +363,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter1.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter1.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } @@ -373,7 +373,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) { proj = proj.AddDocument( Path.GetFileName(filePath), - node.NormalizeWhitespace(), + node, filePath: proj.FullPath(filePath) ).Project; } @@ -385,7 +385,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter2.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter2.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } @@ -397,7 +397,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter3.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter3.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/StripAttributes.cs b/sources/SilkTouch/SilkTouch/Mods/StripAttributes.cs index 9bf511bf3b..c043f71293 100644 --- a/sources/SilkTouch/SilkTouch/Mods/StripAttributes.cs +++ b/sources/SilkTouch/SilkTouch/Mods/StripAttributes.cs @@ -48,7 +48,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformEnums.cs b/sources/SilkTouch/SilkTouch/Mods/TransformEnums.cs index e3fa94640f..e5ee37046e 100644 --- a/sources/SilkTouch/SilkTouch/Mods/TransformEnums.cs +++ b/sources/SilkTouch/SilkTouch/Mods/TransformEnums.cs @@ -190,7 +190,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) var doc = proj.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); proj = doc.WithSyntaxRoot( - rewriter.Visit(await doc.GetSyntaxRootAsync(ct))?.NormalizeWhitespace() + rewriter.Visit(await doc.GetSyntaxRootAsync(ct)) ?? throw new InvalidOperationException("Visit returned null.") ).Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs b/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs index 222c974af8..1d97c3a230 100644 --- a/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs +++ b/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs @@ -60,7 +60,7 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default) proj!.GetDocument(docId) ?? throw new InvalidOperationException("Document missing"); if (await doc.GetSyntaxRootAsync(ct) is { } root) { - proj = doc.WithSyntaxRoot(Visit(root).NormalizeWhitespace()).Project; + proj = doc.WithSyntaxRoot(Visit(root)).Project; } } diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs index 722f1a3b94..c2011b0ba4 100644 --- a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs +++ b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs @@ -115,9 +115,7 @@ [new PointerDimensionReductionTransformer()], var syntaxRoot = await syntaxTree.GetRootAsync(ct); // Rewrite handle struct to include handle members - document = document.WithSyntaxRoot( - handleTypeRewriter.Visit(syntaxRoot).NormalizeWhitespace() - ); + document = document.WithSyntaxRoot(handleTypeRewriter.Visit(syntaxRoot)); project = document.Project; } diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs b/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs index bed5366d8a..4ce2a40291 100644 --- a/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs +++ b/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs @@ -58,7 +58,7 @@ is GenericNameSyntax && lit.IsKind(SyntaxKind.Utf8StringLiteralExpression) ) { - node = node.WithType(IdentifierName("Utf8String")).NormalizeWhitespace(); + node = node.WithType(IdentifierName("Utf8String")); } return base.VisitPropertyDeclaration(node); diff --git a/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs b/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs index ba663df169..9ce3347aac 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Transformation/FunctionTransformer.cs @@ -117,7 +117,6 @@ meth.Body.Statements[0] as ExpressionStatementSyntax .WithBody(null) .WithExpressionBody(null) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) - .NormalizeWhitespace(eol: "\n") .ToFullString() ); continue; From aaafeff2a31d16e1ae602ba7c9f249c33ad5f169 Mon Sep 17 00:00:00 2001 From: William Chen Date: Wed, 15 Apr 2026 23:42:26 -0400 Subject: [PATCH 14/25] Fix issue where the syntax tree gets corrupted due to reparsing (cherry picked from commit 2c48fb6fb73cd3689123beded5e4949b9d1ad8c4) --- sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs index da23b4a6dc..5d614b63e9 100644 --- a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs @@ -221,12 +221,24 @@ await proj.GetCompilationAsync(ct) continue; } + // Save syntax tree so we can restore it later + // Modifying the document can cause it to be reparsed + // C# discord: https://discord.com/channels/143867839282020352/598678594750775301/1494176147351535687 + var syntaxRoot = await doc.GetSyntaxRootAsync(ct); + if (syntaxRoot == null) + { + continue; + } + // Rename doc and update path var originalName = doc.Name; var originalPath = doc.RelativePath(); doc = doc.ReplaceNameAndPath(oldName, newName); var newPath = doc.RelativePath(); + // Restore syntax tree + doc = doc.WithSyntaxRoot(syntaxRoot); + // Check for path conflict documentPaths.Remove(originalPath); if (!documentPaths.Add(newPath)) From f63b15adabdb9cd1fcfa058ba3d4a5c1a9d012db Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 02:30:28 -0400 Subject: [PATCH 15/25] Edit comment and error message (cherry picked from commit 6b12c6979ad9f965332cb06f2821f1b18fca1fde) --- sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs index 5d614b63e9..619eea2197 100644 --- a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs @@ -222,7 +222,7 @@ await proj.GetCompilationAsync(ct) } // Save syntax tree so we can restore it later - // Modifying the document can cause it to be reparsed + // This is because modifying the document can cause it to be reparsed // C# discord: https://discord.com/channels/143867839282020352/598678594750775301/1494176147351535687 var syntaxRoot = await doc.GetSyntaxRootAsync(ct); if (syntaxRoot == null) @@ -244,7 +244,7 @@ await proj.GetCompilationAsync(ct) if (!documentPaths.Add(newPath)) { logger.LogError( - $"{originalName} -> {doc.Name} failed to rename file as a file already exists at {doc.FilePath}" + $"{originalName} -> {doc.Name} failed to rename file as a file already exists at {newPath}" ); continue; From 46c2035f69f91b284d8804f17c940d1d7028071b Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 17:40:06 -0400 Subject: [PATCH 16/25] Avoid normalizing the syntax node twice when formatting --- .../SilkTouch/Mods/Common/MSBuildModContext.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs b/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs index 793a0ed1c7..4ade6bb2a9 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs @@ -308,13 +308,8 @@ private static async Task ToNormalisedStringAsync( CancellationToken ct = default ) { - var result = await CodeFormatter.FormatAsync( - root.NormalizeWhitespace().SyntaxTree, - _opts, - ct - ); - return !result.CompilationErrors.Any() - ? result.Code - : root.NormalizeWhitespace(eol: "\n").ToFullString(); + var normalizedRoot = root.NormalizeWhitespace(); + var result = await CodeFormatter.FormatAsync(normalizedRoot.SyntaxTree, _opts, ct); + return !result.CompilationErrors.Any() ? result.Code : normalizedRoot.ToFullString(); } } From 0d81c6121dc2a10c02c73154eeef9c272e2476db Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 17:45:44 -0400 Subject: [PATCH 17/25] Avoid rebuilding the _relevantIdentifiers set for every document --- .../LocationTransformationRewriter.cs | 26 ++++++++++++++++++- .../LocationTransformationUtils.cs | 6 ++--- .../LocationTransformer.cs | 5 ++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index e0a921de92..5253b0f935 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -51,7 +51,22 @@ List transformers // Used to skip symbol lookups // Does not handle the omission of the "-Attribute" suffix, but generally, we don't need to transform attributes - _relevantIdentifiers = _symbols.Select(s => s.Name).ToHashSet(); + _relevantIdentifiers = new HashSet(_symbols.Count); + foreach (var symbol in _symbols) + { + _relevantIdentifiers.Add(symbol.Name); + } + } + + private LocationTransformationRewriter( + HashSet symbols, + List transformers, + HashSet relevantIdentifiers + ) + { + _symbols = symbols; + _transformers = transformers; + _relevantIdentifiers = relevantIdentifiers; } /// @@ -59,6 +74,15 @@ List transformers /// public void Initialize(SemanticModel semanticModel) => _semanticModel = semanticModel; + /// + /// Clone this rewriter for purposes of thread safety. + /// + /// + /// This is allowed to return the current instance and share data. + /// + public LocationTransformationRewriter GetThreadSafeCopy() => + new(_symbols, [.. _transformers.Select(t => t.GetThreadSafeCopy())], _relevantIdentifiers); + /// [return: NotNullIfNotNull("unmodifiedNode")] public override SyntaxNode? Visit(SyntaxNode? unmodifiedNode) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs index 745230ea4f..fa5e5e3325 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs @@ -53,6 +53,7 @@ public static async Task ModifyAllReferencesAsync( var newDocuments = new ConcurrentDictionary(); var symbolSet = new HashSet(symbols, SymbolEqualityComparer.Default); + var baseRewriter = new LocationTransformationRewriter(symbolSet, transformers.ToList()); await Parallel.ForEachAsync( documentIds, ct, @@ -73,10 +74,7 @@ await Parallel.ForEachAsync( var semanticModel = compilation.GetSemanticModel(originalRoot.SyntaxTree); // Since this is multithreaded, each thread needs their own copy of the rewriter and transformers - var rewriter = new LocationTransformationRewriter( - symbolSet, - [.. transformers.Select(t => t.GetThreadSafeCopy())] - ); + var rewriter = baseRewriter.GetThreadSafeCopy(); rewriter.Initialize(semanticModel); var newRoot = rewriter.Visit(originalRoot); diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs index fa647abd8d..c1c466a171 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformer.cs @@ -31,8 +31,9 @@ ISymbol symbol /// /// Clone this location transformer for purposes of thread safety. - /// If the location transformer is already thread safe, the location transformer - /// does not need to be cloned. /// + /// + /// This is allowed to return the current instance and share data. + /// public abstract LocationTransformer GetThreadSafeCopy(); } From bd2d79cf8287c5aa3e372cf7d6bdae699ea34900 Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 18:13:50 -0400 Subject: [PATCH 18/25] Move collections in ResolveConflictsProcessor to be closer to where they are used --- .../SilkTouch/SilkTouch/Mods/PrettifyNames.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs index 619eea2197..afccdb95ab 100644 --- a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs +++ b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs @@ -1132,17 +1132,6 @@ public void ProcessNames(NameProcessorContext context) } } - // These collections are used later. - // These keep track of method discriminators to determine whether we have incompatible overloads. - // We keep track of the first original name so that we can add it to conflictingOriginalNames when we - // do discover a conflict (along with the original name of the actual conflict). - var methodDiscriminators = - new Dictionary< - string, - (string? FirstOriginalName, List Methods) - >(); - var conflictingOriginalNames = new HashSet(); - // This loop cannot be part of the loop below because it modifies the primaries foreach (var (scope, members) in context.Names) { @@ -1208,6 +1197,17 @@ d is not MethodDeclarationSyntax } } + // These collections are used later. + // These keep track of method discriminators to determine whether we have incompatible overloads. + // We keep track of the first original name so that we can add it to conflictingOriginalNames when we + // do discover a conflict (along with the original name of the actual conflict). + var methodDiscriminators = + new Dictionary< + string, + (string? FirstOriginalName, List Methods) + >(); + var conflictingOriginalNames = new HashSet(); + foreach (var (scope, members) in context.Names) { nameData.Names.TryGetValue(scope, out var scopeData); From 364015d48af8dc6b5e32704b7a2caab5de0c4087 Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 18:48:51 -0400 Subject: [PATCH 19/25] Preserve original line ending behavior (cherry picked from commit 66d0daabc1a459bec1d4a60d9fbc787f62f8b845) --- sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs b/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs index 4ade6bb2a9..55bcbcf113 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs @@ -308,7 +308,7 @@ private static async Task ToNormalisedStringAsync( CancellationToken ct = default ) { - var normalizedRoot = root.NormalizeWhitespace(); + var normalizedRoot = root.NormalizeWhitespace(eol: "\n"); var result = await CodeFormatter.FormatAsync(normalizedRoot.SyntaxTree, _opts, ct); return !result.CompilationErrors.Any() ? result.Code : normalizedRoot.ToFullString(); } From 00d83bcde61c48ce3ca7b85eb837c3b5407f3da8 Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 19:56:22 -0400 Subject: [PATCH 20/25] Update SDL to v3.44 from v3.2.4 to fix compile error --- eng/submodules/sdl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/submodules/sdl b/eng/submodules/sdl index b5c3eab6b4..5848e584a1 160000 --- a/eng/submodules/sdl +++ b/eng/submodules/sdl @@ -1 +1 @@ -Subproject commit b5c3eab6b447111d3c7879bb547b80fb4abd9063 +Subproject commit 5848e584a1b606de26e3dbd1c7e4ecbc34f807a6 From aa13c486b3e924c08dc389dffa5d9fecec9ca82a Mon Sep 17 00:00:00 2001 From: William Chen Date: Thu, 16 Apr 2026 20:07:01 -0400 Subject: [PATCH 21/25] Revert change to get the compilation once during ModifyAllReferencesAsync This change caused incorrect behavior since the document ids can come from projects other than the source project (namely the test project). This broken when semantic models were requested for test project documents from the source project compilation. --- .../LocationTransformationUtils.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs index fa5e5e3325..a2faa241f3 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs @@ -45,12 +45,6 @@ public static async Task ModifyAllReferencesAsync( ]; var originalSolution = sourceProject.Solution; - var compilation = await sourceProject.GetCompilationAsync(ct); - if (compilation == null) - { - return; - } - var newDocuments = new ConcurrentDictionary(); var symbolSet = new HashSet(symbols, SymbolEqualityComparer.Default); var baseRewriter = new LocationTransformationRewriter(symbolSet, transformers.ToList()); @@ -66,13 +60,12 @@ await Parallel.ForEachAsync( } var originalRoot = await originalDocument.GetSyntaxRootAsync(ct); - if (originalRoot == null) + var semanticModel = await originalDocument.GetSemanticModelAsync(ct); + if (originalRoot == null || semanticModel == null) { return; } - var semanticModel = compilation.GetSemanticModel(originalRoot.SyntaxTree); - // Since this is multithreaded, each thread needs their own copy of the rewriter and transformers var rewriter = baseRewriter.GetThreadSafeCopy(); From 7d56e23c473cf1da7271f4e7d660ca5158582357 Mon Sep 17 00:00:00 2001 From: William Chen Date: Fri, 17 Apr 2026 18:01:43 -0400 Subject: [PATCH 22/25] Revert "Update SDL to v3.44 from v3.2.4 to fix compile error" This reverts commit 00d83bcde61c48ce3ca7b85eb837c3b5407f3da8. --- eng/submodules/sdl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/submodules/sdl b/eng/submodules/sdl index 5848e584a1..b5c3eab6b4 160000 --- a/eng/submodules/sdl +++ b/eng/submodules/sdl @@ -1 +1 @@ -Subproject commit 5848e584a1b606de26e3dbd1c7e4ecbc34f807a6 +Subproject commit b5c3eab6b447111d3c7879bb547b80fb4abd9063 From 07e05f0cff399b98024d206c1afa1185fb4f43d3 Mon Sep 17 00:00:00 2001 From: William Chen Date: Fri, 17 Apr 2026 18:02:13 -0400 Subject: [PATCH 23/25] Revert "Update ClangSharp.PInvokeGenerator" This reverts commit 7938a0cbb3a52005a361de0e338098f18babeb42. --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 385845b466..0c0cf4d13b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -21,7 +21,7 @@ - + From 514b866c90f39fe63d0526b15941c1a1265eee01 Mon Sep 17 00:00:00 2001 From: William Chen Date: Fri, 17 Apr 2026 18:21:45 -0400 Subject: [PATCH 24/25] Revert "Preserve original line ending behavior" This reverts commit 364015d48af8dc6b5e32704b7a2caab5de0c4087. --- sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs b/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs index 55bcbcf113..4ade6bb2a9 100644 --- a/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs +++ b/sources/SilkTouch/SilkTouch/Mods/Common/MSBuildModContext.cs @@ -308,7 +308,7 @@ private static async Task ToNormalisedStringAsync( CancellationToken ct = default ) { - var normalizedRoot = root.NormalizeWhitespace(eol: "\n"); + var normalizedRoot = root.NormalizeWhitespace(); var result = await CodeFormatter.FormatAsync(normalizedRoot.SyntaxTree, _opts, ct); return !result.CompilationErrors.Any() ? result.Code : normalizedRoot.ToFullString(); } From 1f1428ed263a894af568e4364b95c6bc4698ff07 Mon Sep 17 00:00:00 2001 From: William Chen Date: Fri, 17 Apr 2026 18:25:26 -0400 Subject: [PATCH 25/25] Add comment on why UsingDirectiveSyntaxes are skipped --- .../LocationTransformation/LocationTransformationRewriter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs index 5253b0f935..213ea19db5 100644 --- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs +++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs @@ -313,6 +313,7 @@ public override SyntaxNode VisitVariableDeclarator(VariableDeclaratorSyntax node // ----- Skipped nodes ----- + // Using statements contain a lot of identifier nodes, but never any symbol references that we care about. /// public override SyntaxNode VisitUsingDirective(UsingDirectiveSyntax node) => node; }