@@ -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>
116137public 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
153210public 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 {
0 commit comments