Skip to content

Commit b11287e

Browse files
committed
Preserve existing type arg syntax in code fix
When explicit generic type arguments already exist, preserve the original syntax nodes and only replace the one being fixed. This avoids MinimallyQualifiedFormat potentially producing uncompilable type names. 🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 9705249 commit b11287e

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

tracer/src/Datadog.Trace.Tools.Analyzers.CodeFixes/AllocationAnalyzer/RemoveNumericToStringCodeFixProvider.cs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -132,22 +132,25 @@ private static async Task<Document> RemoveToStringAsync(
132132
return document.WithSyntaxRoot(root);
133133
}
134134

135-
// Build the new type argument list, replacing the type at the right index
136-
var typeArgs = methodSymbol.TypeArguments
137-
.Select((t, i) => i == typeArgIndex ? numericKeyword : GetTypeKeyword(t))
138-
.Select(keyword => SyntaxFactory.ParseTypeName(keyword))
139-
.ToArray();
140-
141-
var newTypeArgList = SyntaxFactory.TypeArgumentList(
142-
SyntaxFactory.SeparatedList(typeArgs));
143-
144135
// Check if the log call already has explicit generic type arguments
145136
if (logInvocation.Expression is MemberAccessExpressionSyntax logMemberAccess
146137
&& logMemberAccess.Name is GenericNameSyntax existingGenericName)
147138
{
148-
// Update existing explicit type args
149-
var newGenericName = existingGenericName.WithTypeArgumentList(
150-
newTypeArgList.WithTriviaFrom(existingGenericName.TypeArgumentList));
139+
// Preserve existing type arg syntax nodes, only replace the one being fixed
140+
var existingTypeArgs = existingGenericName.TypeArgumentList.Arguments;
141+
var newTypeArgs = new TypeSyntax[existingTypeArgs.Count];
142+
for (var i = 0; i < existingTypeArgs.Count; i++)
143+
{
144+
newTypeArgs[i] = i == typeArgIndex
145+
? SyntaxFactory.ParseTypeName(numericKeyword).WithTriviaFrom(existingTypeArgs[i])
146+
: existingTypeArgs[i];
147+
}
148+
149+
var newTypeArgList = SyntaxFactory.TypeArgumentList(
150+
SyntaxFactory.SeparatedList(newTypeArgs))
151+
.WithTriviaFrom(existingGenericName.TypeArgumentList);
152+
153+
var newGenericName = existingGenericName.WithTypeArgumentList(newTypeArgList);
151154

152155
var nodesToReplace = new SyntaxNode[]
153156
{
@@ -169,7 +172,15 @@ private static async Task<Document> RemoveToStringAsync(
169172
else if (logInvocation.Expression is MemberAccessExpressionSyntax simpleMemberAccess
170173
&& simpleMemberAccess.Name is IdentifierNameSyntax identifierName)
171174
{
172-
// No explicit generic type args — add them to avoid overload ambiguity
175+
// No explicit generic type args — build from method symbol and add them
176+
var typeArgs = methodSymbol.TypeArguments
177+
.Select((t, i) => i == typeArgIndex ? numericKeyword : GetTypeKeyword(t))
178+
.Select(keyword => SyntaxFactory.ParseTypeName(keyword))
179+
.ToArray();
180+
181+
var newTypeArgList = SyntaxFactory.TypeArgumentList(
182+
SyntaxFactory.SeparatedList(typeArgs));
183+
173184
var newGenericName = SyntaxFactory.GenericName(identifierName.Identifier, newTypeArgList);
174185

175186
var newLogExpression = simpleMemberAccess.WithName(newGenericName);

0 commit comments

Comments
 (0)