Skip to content

Commit cea55da

Browse files
committed
Fix ArgumentOutOfRangeException and replace old renamer
1 parent 3f93134 commit cea55da

5 files changed

Lines changed: 24 additions & 228 deletions

File tree

.silktouch/a8a82533527277ff.stout

0 Bytes
Binary file not shown.

sources/SilkTouch/SilkTouch/Mods/LocationTransformation/IdentifierRenamingTransformer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Microsoft.CodeAnalysis;
5-
using Microsoft.CodeAnalysis.CSharp;
65
using Microsoft.CodeAnalysis.CSharp.Syntax;
6+
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
77

88
namespace Silk.NET.SilkTouch.Mods.LocationTransformation;
99

@@ -36,11 +36,11 @@ public class IdentifierRenamingTransformer(IEnumerable<(ISymbol Symbol, string N
3636
return current;
3737
}
3838

39-
private SyntaxToken GetNewName() => SyntaxFactory.Identifier(_newNameLookup[_context.Symbol]);
39+
private SyntaxToken GetNewName() => Identifier(_newNameLookup[_context.Symbol]);
4040

4141
/// <inheritdoc />
4242
public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
43-
=> SyntaxFactory.IdentifierName(GetNewName());
43+
=> IdentifierName(GetNewName());
4444

4545
// ----- Types -----
4646

sources/SilkTouch/SilkTouch/Mods/LocationTransformation/LocationTransformationUtils.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.CodeAnalysis;
77
using Microsoft.CodeAnalysis.FindSymbols;
88
using Microsoft.Extensions.Logging;
9+
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
910

1011
namespace Silk.NET.SilkTouch.Mods.LocationTransformation;
1112

@@ -95,7 +96,7 @@ await Parallel.ForEachAsync(
9596
// Modify each location
9697
// We order the locations so that we modify starting from the end of the file
9798
// This way we prevent changes from being accidentally overwriting changes
98-
foreach (var (location, context) in group.OrderByDescending(l => l.Location.SourceSpan.Start))
99+
foreach (var (location, context) in group.OrderByDescending(l => l.Location.SourceSpan))
99100
{
100101
foreach (var transformer in transformersList)
101102
{
@@ -107,12 +108,23 @@ await Parallel.ForEachAsync(
107108
}
108109

109110
var newNode = transformer.Visit(nodeToModify);
111+
var originalLength = syntaxNode.FullSpan.Length;
112+
var newLength = newNode.FullSpan.Length;
113+
114+
// Ensure that the new node's length is at least the original node's length
115+
// This is because the last few nodes processed usually make up the entire document
116+
// If the document's length has been reduced, then an ArgumentOutOfRangeException will be thrown
117+
if (originalLength - newLength > 0)
118+
{
119+
newNode = newNode.WithTrailingTrivia(TriviaList([..newNode.GetTrailingTrivia(), Whitespace(new string(' ', originalLength - newLength))]));
120+
}
121+
110122
syntaxRoot = syntaxRoot.ReplaceNode(nodeToModify, newNode);
111123
}
112124
}
113125

114126
// Commit the changes to the project
115-
var newDocument = document.WithSyntaxRoot(syntaxRoot);
127+
var newDocument = document.WithSyntaxRoot(syntaxRoot.NormalizeWhitespace());
116128
project = newDocument.Project;
117129
}
118130

sources/SilkTouch/SilkTouch/Mods/PrettifyNames.cs

Lines changed: 2 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,9 @@ await proj.GetCompilationAsync(ct)
273273
?? throw new InvalidOperationException(
274274
"Failed to obtain compilation for source project!"
275275
);
276-
await RenameAllAsync(
276+
await NameUtils.RenameAllAsync(
277277
ctx,
278+
logger,
278279
types.SelectMany(x =>
279280
{
280281
var nonFunctionConflicts = x
@@ -952,117 +953,6 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
952953
_ => null
953954
};
954955

955-
private async Task RenameAllAsync(
956-
IModContext ctx,
957-
IEnumerable<(ISymbol Symbol, string NewName)> toRename,
958-
CancellationToken ct = default
959-
)
960-
{
961-
if (ctx.SourceProject is null)
962-
{
963-
return;
964-
}
965-
966-
var locations = new ConcurrentDictionary<Location, string>();
967-
// TODO this needs parallelisation config & be sensitive to the environment (future src generator form factor?)
968-
await Parallel.ForEachAsync(
969-
toRename,
970-
ct,
971-
async (tuple, _) =>
972-
{
973-
// First, let's add all of the locations of the declaration identifiers.
974-
var (symbol, newName) = tuple;
975-
foreach (var syntaxRef in symbol.DeclaringSyntaxReferences)
976-
{
977-
var identifierLocation = IdentifierLocation(await syntaxRef.GetSyntaxAsync(ct));
978-
if (identifierLocation is not null)
979-
{
980-
locations.TryAdd(identifierLocation, newName);
981-
}
982-
}
983-
984-
// Next, let's find all the references of the symbols.
985-
var references = await SymbolFinder.FindReferencesAsync(
986-
symbol,
987-
ctx.SourceProject?.Solution
988-
?? throw new ArgumentException("SourceProject is null"),
989-
ct
990-
);
991-
992-
foreach (var referencedSymbol in references)
993-
{
994-
foreach (var referencedSymbolLocation in referencedSymbol.Locations)
995-
{
996-
if (
997-
referencedSymbolLocation.IsCandidateLocation
998-
|| referencedSymbolLocation.IsImplicit
999-
)
1000-
{
1001-
continue;
1002-
}
1003-
1004-
locations.TryAdd(referencedSymbolLocation.Location, newName);
1005-
}
1006-
}
1007-
}
1008-
);
1009-
1010-
logger.LogDebug("{} referencing locations for renames for {}", locations.Count, ctx.JobKey);
1011-
1012-
// Now it's just a simple find and replace.
1013-
var sln = ctx.SourceProject.Solution;
1014-
var srcProjId = ctx.SourceProject.Id;
1015-
var testProjId = ctx.TestProject?.Id;
1016-
foreach (
1017-
var (syntaxTree, renameLocations) in locations
1018-
.GroupBy(x => x.Key.SourceTree)
1019-
.Select(x => (x.Key, x.OrderByDescending(y => y.Key.SourceSpan)))
1020-
)
1021-
{
1022-
if (
1023-
syntaxTree is null
1024-
|| sln.GetDocument(syntaxTree) is not { } doc
1025-
|| (doc.Project.Id != srcProjId && doc.Project.Id != testProjId)
1026-
|| await syntaxTree.GetTextAsync(ct) is not { } text
1027-
)
1028-
{
1029-
continue;
1030-
}
1031-
1032-
var ogText = text;
1033-
foreach (var (location, newName) in renameLocations)
1034-
{
1035-
var contents = ogText.GetSubText(location.SourceSpan).ToString();
1036-
if (contents.Contains(' '))
1037-
{
1038-
logger.LogWarning(
1039-
"Refusing to do unsafe rename/replacement of \"{}\" to \"{}\" at {}",
1040-
contents,
1041-
newName,
1042-
location.GetLineSpan()
1043-
);
1044-
continue;
1045-
}
1046-
1047-
if (logger.IsEnabled(LogLevel.Trace))
1048-
{
1049-
logger.LogTrace(
1050-
"\"{}\" -> \"{}\" at {}",
1051-
contents,
1052-
newName,
1053-
location.GetLineSpan()
1054-
);
1055-
}
1056-
1057-
text = text.Replace(location.SourceSpan, newName);
1058-
}
1059-
1060-
sln = doc.WithText(text).Project.Solution;
1061-
}
1062-
1063-
ctx.SourceProject = sln.GetProject(srcProjId);
1064-
}
1065-
1066956
/// <inheritdoc />
1067957
public Task<List<ResponseFile>> BeforeScrapeAsync(string key, List<ResponseFile> rsps)
1068958
{

sources/SilkTouch/SilkTouch/Naming/NameUtils.cs

Lines changed: 5 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Microsoft.CodeAnalysis.FindSymbols;
1717
using Microsoft.Extensions.Logging;
1818
using Silk.NET.SilkTouch.Mods;
19+
using Silk.NET.SilkTouch.Mods.LocationTransformation;
1920
using Project = Microsoft.CodeAnalysis.Project;
2021

2122
namespace Silk.NET.SilkTouch.Naming;
@@ -348,116 +349,9 @@ public static async Task RenameAllAsync(
348349
bool includeCandidateLocations = false
349350
)
350351
{
351-
if (ctx.SourceProject is null)
352-
{
353-
return;
354-
}
355-
356-
var locations = new ConcurrentDictionary<Location, string>();
357-
// TODO this needs parallelisation config & be sensitive to the environment (future src generator form factor?)
358-
await Parallel.ForEachAsync(
359-
toRename,
360-
ct,
361-
async (tuple, _) =>
362-
{
363-
// First, let's add all of the locations of the declaration identifiers.
364-
var (symbol, newName) = tuple;
365-
if (includeDeclarations)
366-
{
367-
foreach (var syntaxRef in symbol.DeclaringSyntaxReferences)
368-
{
369-
var identifierLocation = IdentifierLocation(
370-
await syntaxRef.GetSyntaxAsync(ct)
371-
);
372-
if (identifierLocation is not null)
373-
{
374-
locations.TryAdd(identifierLocation, newName);
375-
}
376-
}
377-
}
378-
379-
// Next, let's find all the references of the symbols.
380-
var references = await SymbolFinder.FindReferencesAsync(
381-
symbol,
382-
ctx.SourceProject?.Solution
383-
?? throw new ArgumentException("SourceProject is null"),
384-
ct
385-
);
386-
387-
foreach (var referencedSymbol in references)
388-
{
389-
foreach (var referencedSymbolLocation in referencedSymbol.Locations)
390-
{
391-
if (
392-
!includeCandidateLocations
393-
&& (
394-
referencedSymbolLocation.IsCandidateLocation
395-
|| referencedSymbolLocation.IsImplicit
396-
)
397-
)
398-
{
399-
continue;
400-
}
401-
402-
locations.TryAdd(referencedSymbolLocation.Location, newName);
403-
}
404-
}
405-
}
406-
);
407-
408-
logger.LogDebug("{} referencing locations for renames for {}", locations.Count, ctx.JobKey);
409-
410-
// Now it's just a simple find and replace.
411-
var sln = ctx.SourceProject.Solution;
412-
var srcProjId = ctx.SourceProject.Id;
413-
var testProjId = ctx.TestProject?.Id;
414-
foreach (
415-
var (syntaxTree, renameLocations) in locations
416-
.GroupBy(x => x.Key.SourceTree)
417-
.Select(x => (x.Key, x.OrderByDescending(y => y.Key.SourceSpan)))
418-
)
419-
{
420-
if (
421-
syntaxTree is null
422-
|| sln.GetDocument(syntaxTree) is not { } doc
423-
|| (doc.Project.Id != srcProjId && doc.Project.Id != testProjId)
424-
|| await syntaxTree.GetTextAsync(ct) is not { } text
425-
)
426-
{
427-
continue;
428-
}
429-
430-
var ogText = text;
431-
foreach (var (location, newName) in renameLocations)
432-
{
433-
var contents = ogText.GetSubText(location.SourceSpan).ToString();
434-
if (contents.Contains(' '))
435-
{
436-
logger.LogWarning(
437-
"Refusing to do unsafe rename/replacement of \"{}\" to \"{}\" at {}",
438-
contents,
439-
newName,
440-
location.GetLineSpan()
441-
);
442-
continue;
443-
}
444-
445-
if (logger.IsEnabled(LogLevel.Trace))
446-
{
447-
logger.LogTrace(
448-
"\"{}\" -> \"{}\" at {}",
449-
contents,
450-
newName,
451-
location.GetLineSpan()
452-
);
453-
}
454-
455-
text = text.Replace(location.SourceSpan, newName);
456-
}
457-
458-
sln = doc.WithText(text).Project.Solution;
459-
}
460-
461-
ctx.SourceProject = sln.GetProject(srcProjId);
352+
var toRenameList = toRename.ToList();
353+
await LocationTransformationUtils.ModifyAllReferencesAsync(ctx, logger, toRenameList.Select(t => t.Symbol), [
354+
new IdentifierRenamingTransformer(toRenameList)
355+
], ct);
462356
}
463357
}

0 commit comments

Comments
 (0)