Skip to content

Commit 8557c7b

Browse files
committed
Attempt to implement renaming functionality with LocationTransformers
1 parent 11dff8b commit 8557c7b

3 files changed

Lines changed: 96 additions & 63 deletions

File tree

.silktouch/a8a82533527277ff.stout

0 Bytes
Binary file not shown.

sources/SilkTouch/SilkTouch/Mods/LocationTransformation/PointerDimensionReductionTransformer.cs

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ public static async Task ModifyAllReferencesAsync(
2828
IEnumerable<LocationTransformer> transformers,
2929
CancellationToken ct = default)
3030
{
31-
var symbolSet = symbols.ToList();
32-
var transformersSet = transformers.ToList();
31+
// Convert to lists
32+
// The parameters being IEnumerables is for convenience
33+
var symbolList = symbols.ToList();
34+
var transformersList = transformers.ToList();
3335

3436
var project = ctx.SourceProject;
3537
if (project == null)
@@ -43,20 +45,33 @@ public static async Task ModifyAllReferencesAsync(
4345
return;
4446
}
4547

48+
var locations = new ConcurrentBag<(Location Location, LocationTransformerContext Context)>();
49+
50+
// Add the locations of the declaration identifiers for each symbol
51+
foreach (var symbol in symbolList)
52+
{
53+
foreach (var declaringSyntaxReference in symbol.DeclaringSyntaxReferences)
54+
{
55+
locations.Add((declaringSyntaxReference.GetSyntax().GetLocation(),
56+
new LocationTransformerContext(symbol, true, false)));
57+
}
58+
}
59+
4660
// Find all locations where the symbols are referenced
47-
var documents = project.Documents.ToImmutableHashSet();
48-
var locations = new ConcurrentBag<(ISymbol Symbol, Location Location)>();
4961
// TODO this needs parallelisation config & be sensitive to the environment (future src generator form factor?)
62+
var documents = project.Documents.ToImmutableHashSet();
5063
await Parallel.ForEachAsync(
51-
symbolSet,
64+
symbolList,
5265
ct,
5366
async (symbol, _) => {
5467
var references = await SymbolFinder.FindReferencesAsync(symbol, project.Solution, documents, ct);
5568
foreach (var reference in references)
5669
{
5770
foreach (var location in reference.Locations)
5871
{
59-
locations.Add((symbol, location.Location));
72+
locations.Add((location.Location,
73+
new LocationTransformerContext(symbol, false,
74+
location.IsCandidateLocation || location.IsImplicit)));
6075
}
6176
}
6277
}
@@ -83,12 +98,12 @@ await Parallel.ForEachAsync(
8398
// Modify each location
8499
// We order the locations so that we modify starting from the end of the file
85100
// This way we prevent changes from being accidentally overwriting changes
86-
foreach (var (symbol, location) in group.OrderByDescending(l => l.Location.SourceSpan.Start))
101+
foreach (var (location, context) in group.OrderByDescending(l => l.Location.SourceSpan.Start))
87102
{
88-
foreach (var transformer in transformersSet)
103+
foreach (var transformer in transformersList)
89104
{
90105
var syntaxNode = syntaxRoot.FindNode(location.SourceSpan);
91-
var nodeToModify = transformer.GetNodeToModify(syntaxNode, symbol);
106+
var nodeToModify = transformer.GetNodeToModify(syntaxNode, context);
92107
if (nodeToModify == null)
93108
{
94109
continue;
@@ -97,8 +112,6 @@ await Parallel.ForEachAsync(
97112
var newNode = transformer.Visit(nodeToModify);
98113
syntaxRoot = syntaxRoot.ReplaceNode(nodeToModify, newNode);
99114
}
100-
101-
102115
}
103116

104117
// Commit the changes to the project
@@ -110,37 +123,81 @@ await Parallel.ForEachAsync(
110123
}
111124
}
112125

126+
/// <summary>
127+
/// Additional information about the syntax node being processed.
128+
/// </summary>
129+
/// <param name="Symbol">The symbol used to find the node.</param>
130+
/// <param name="IsDeclaration">Does the syntax node represent the declaration of the symbol?</param>
131+
/// <param name="IsCandidateLocation">Does the syntax node represent a candidate location?</param>
132+
public record struct LocationTransformerContext(ISymbol Symbol, bool IsDeclaration, bool IsCandidateLocation);
133+
113134
/// <summary>
114135
/// Base class for location transformers used by <see cref="LocationTransformationUtils.ModifyAllReferencesAsync"/>.
115136
/// </summary>
116137
public abstract class LocationTransformer : CSharpSyntaxRewriter
117138
{
118139
/// <summary>
119-
/// Given a node, this method should return a parent node, the given node, or null.
140+
/// Given a node, this method should return the given node, another node, or null.
120141
/// Returning null will lead to no node being modified.
121-
/// Returning the parent node will lead to the parent node being modified instead of the original node.
142+
/// Returning the another node will lead to the other node being modified instead of the original node.
122143
/// </summary>
123144
/// <param name="current">The current node.</param>
124-
/// <param name="symbol">The symbol that was used to find the current node.</param>
125-
/// <returns>The parent of the given node, the given node, or null.</returns>
126-
public abstract SyntaxNode? GetNodeToModify(SyntaxNode current, ISymbol symbol);
145+
/// <param name="context">Additional information about the syntax node being processed.</param>
146+
/// <returns>The given node, another node, or null.</returns>
147+
public abstract SyntaxNode? GetNodeToModify(SyntaxNode current, LocationTransformerContext context);
127148
}
128149

129-
// // TODO: Implement this
130-
// /// <summary>
131-
// /// Renames the identifiers for all locations transformed.
132-
// /// </summary>
133-
// public class IdentifierRenamingTransformer(bool includeDeclarations = true, bool includeCandidateLocations = false) : LocationTransformer
134-
// {
135-
// /// <inheritdoc />
136-
// public override SyntaxNode? GetNodeToModify(SyntaxNode current, ISymbol symbol) => current;
137-
//
138-
// /// <inheritdoc />
139-
// public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
140-
// {
141-
// return IdentifierName("Equals");
142-
// }
143-
// }
150+
/// <summary>
151+
/// Renames the identifiers for all locations transformed.
152+
/// </summary>
153+
/// <param name="newNamesBySymbol">The new names for each symbol as a dictionary.</param>
154+
/// <param name="includeDeclarations">Should declaration references be renamed?</param>
155+
/// <param name="includeCandidateLocations">Should candidate references or implicit references be renamed?</param>
156+
public class IdentifierRenamingTransformer(IEnumerable<(ISymbol Symbol, string NewName)> newNamesBySymbol, bool includeDeclarations = true, bool includeCandidateLocations = false) : LocationTransformer
157+
{
158+
private LocationTransformerContext _context;
159+
private Dictionary<ISymbol, string> _newNameLookup = newNamesBySymbol.Select(t => new KeyValuePair<ISymbol, string>(t.Symbol, t.NewName)).ToDictionary(SymbolEqualityComparer.Default);
160+
161+
/// <inheritdoc />
162+
public override SyntaxNode? GetNodeToModify(SyntaxNode current, LocationTransformerContext context)
163+
{
164+
_context = context;
165+
166+
if (!includeDeclarations && context.IsDeclaration)
167+
{
168+
return null;
169+
}
170+
171+
if (!includeCandidateLocations && context.IsCandidateLocation)
172+
{
173+
return null;
174+
}
175+
176+
return current;
177+
}
178+
179+
/// <inheritdoc />
180+
public override SyntaxNode? DefaultVisit(SyntaxNode node)
181+
{
182+
var newName = _newNameLookup[_context.Symbol];
183+
var newNameToken = Identifier(newName);
184+
185+
return node switch
186+
{
187+
IdentifierNameSyntax => IdentifierName(newNameToken),
188+
BaseTypeDeclarationSyntax bt => bt.WithIdentifier(newNameToken),
189+
DelegateDeclarationSyntax d => d.WithIdentifier(newNameToken),
190+
EnumMemberDeclarationSyntax em => em.WithIdentifier(newNameToken),
191+
EventDeclarationSyntax e => e.WithIdentifier(newNameToken),
192+
MethodDeclarationSyntax m => m.WithIdentifier(newNameToken),
193+
PropertyDeclarationSyntax p => p.WithIdentifier(newNameToken),
194+
VariableDeclaratorSyntax v => v.WithIdentifier(newNameToken),
195+
ConstructorDeclarationSyntax c => c.WithIdentifier(newNameToken),
196+
DestructorDeclarationSyntax d => d.WithIdentifier(newNameToken),
197+
_ => node,
198+
};
199+
}
200+
}
144201

145202
/// <summary>
146203
/// Reduces the pointer dimension by one for all locations transformed.
@@ -153,7 +210,7 @@ public abstract class LocationTransformer : CSharpSyntaxRewriter
153210
public class PointerDimensionReductionTransformer : LocationTransformer
154211
{
155212
/// <inheritdoc />
156-
public override SyntaxNode? GetNodeToModify(SyntaxNode current, ISymbol symbol)
213+
public override SyntaxNode? GetNodeToModify(SyntaxNode current, LocationTransformerContext context)
157214
{
158215
if (current.Parent is PointerTypeSyntax parent)
159216
{

sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,39 +96,15 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct =
9696
}
9797
}
9898

99-
// Get fully qualified metadata names for each handle type
100-
// This is because symbols are invalidated after modifying the project they come from
101-
// We use these names to restore the symbols
102-
// TODO: This actually requires rewriting the fully qualified metadata names since the names will be different after the rename below. AHHHH...
103-
// Rewriting RenameAllAsync to allow providing a list of CSharpSyntaxRewriters might work best
104-
var handleTypeMetadataNames = handleTypes
105-
.Select(t => {
106-
var ns = t.NamespaceFromSymbol();
107-
var name = string.IsNullOrEmpty(ns) ? t.Name : $"{ns}.{t.Name}";
108-
109-
return name.Replace(t.Name, $"{t.Name}Handle");
110-
});
111-
11299
// Phase 2. Modify project after gathering data
113-
// Add -Handle suffix
114-
ctx.SourceProject = project;
115-
await NameUtils.RenameAllAsync(ctx, logger, handleTypes.Select(t => ((ISymbol)t, $"{t.Name}Handle")), ct);
116-
project = ctx.SourceProject;
117-
118-
// Get the compilation again
119-
compilation = await project.GetCompilationAsync(ct);
120-
if (compilation == null)
121-
{
122-
throw new InvalidOperationException("Failed to get compilation");
123-
}
124-
125-
// Restore symbols invalidated by previous modification
126-
handleTypes = handleTypeMetadataNames.SelectMany(name => compilation.GetTypesByMetadataName(name)).ToList();
127-
128-
// Reduce pointer dimensions
100+
// Do the two following transformation to all references of the handle types:
101+
// 1. Add -Handle suffix
102+
// 2. Reduce pointer dimensions
129103
ctx.SourceProject = project;
130-
await LocationTransformationUtils.ModifyAllReferencesAsync(ctx, logger, handleTypes,
131-
[new PointerDimensionReductionTransformer()], ct);
104+
await LocationTransformationUtils.ModifyAllReferencesAsync(ctx, logger, handleTypes, [
105+
new PointerDimensionReductionTransformer(),
106+
new IdentifierRenamingTransformer(handleTypes.Select(t => ((ISymbol)t, $"{t.Name}Handle")))
107+
], ct);
132108
project = ctx.SourceProject;
133109

134110
// Use document IDs from earlier

0 commit comments

Comments
 (0)