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 @@
-
+
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..e0a921de92 100644
--- a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationRewriter.cs
@@ -14,36 +14,50 @@ 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;
+
+ // 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();
+ }
///
/// 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")]
@@ -60,24 +74,25 @@ 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];
- modifiedNode = deferredTransformer.Visit(modifiedNode)
+ var deferredTransformer = _transformers[transformation.TransformerIndex];
+ modifiedNode = deferredTransformer
+ .Visit(modifiedNode)
.WithLeadingTrivia(unmodifiedNode.GetLeadingTrivia().Select(VisitTrivia))
.WithTrailingTrivia(unmodifiedNode.GetTrailingTrivia());
}
// 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();
@@ -105,13 +120,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());
}
@@ -122,12 +141,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 -----
@@ -135,7 +154,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)!;
@@ -144,7 +163,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)!;
@@ -153,7 +172,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)!;
@@ -162,7 +181,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)!;
@@ -171,7 +190,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)!;
@@ -180,7 +199,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)!;
@@ -191,7 +210,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)!;
@@ -200,7 +219,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)!;
@@ -209,7 +228,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)!;
@@ -218,7 +237,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)!;
@@ -227,7 +246,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)!;
@@ -236,7 +255,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)!;
@@ -247,7 +266,12 @@ public override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSynta
///
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
{
- var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetTypeInfo(node).Type;
+ if (!_relevantIdentifiers.Contains(node.Identifier.Text))
+ {
+ return node;
+ }
+
+ var symbol = _semanticModel.GetSymbolInfo(node).Symbol;
ReportSymbol(node, symbol);
return base.VisitIdentifierName(node)!;
@@ -257,9 +281,14 @@ 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)!;
}
+
+ // ----- Skipped nodes -----
+
+ ///
+ public override SyntaxNode VisitUsingDirective(UsingDirectiveSyntax node) => node;
}
diff --git a/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs b/sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs
index 8ae9303d72..745230ea4f 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,51 @@ 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 compilation = await sourceProject.GetCompilationAsync(ct);
+ if (compilation == null)
+ {
+ return;
+ }
+
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);
+ if (originalRoot == null)
+ {
+ return;
+ }
- 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 = 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.
diff --git a/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs b/sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs
index 100f43ad25..da23b4a6dc 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.RelativePath())
+ .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,24 @@ await proj.GetCompilationAsync(ct)
continue;
}
+ // Rename doc and update path
var originalName = doc.Name;
+ var originalPath = doc.RelativePath();
doc = doc.ReplaceNameAndPath(oldName, newName);
+ var newPath = doc.RelativePath();
- 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(newPath))
{
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;
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,
diff --git a/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs b/sources/SilkTouch/SilkTouch/Profiling/ProfilingScope.cs
new file mode 100644
index 0000000000..03989bda03
--- /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)
+ {
+ _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
+ );
+ }
+}