Skip to content

Commit 32a1c03

Browse files
paulirwinclaude
andcommitted
Fix LuceneDev2000 codefix to insert IFormatProvider before out arg
TryParse signatures place the IFormatProvider before the trailing `out` parameter (e.g. `bool TryParse(string, IFormatProvider, out double)`), not at the end. The codefix was appending, producing a call that did not bind to any overload. Adds a regression test that fixes `double.TryParse("1.5", out _)` and expects the provider to land in the correct slot. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 514060d commit 32a1c03

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

src/Lucene.Net.CodeAnalysis.Dev.CodeFixes/LuceneDev2xxx/LuceneDev2000_2001_2002_2004_AddInvariantCultureCodeFixProvider.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ private static async Task<Document> AddCultureArgumentAsync(
8181
SyntaxFactory.IdentifierName(cultureMember));
8282
var newArg = SyntaxFactory.Argument(cultureExpr);
8383

84-
var newInvocation = invocation.WithArgumentList(invocation.ArgumentList.AddArguments(newArg));
84+
// For TryParse-style methods, the IFormatProvider must come BEFORE the trailing
85+
// `out` argument: bool TryParse(string, IFormatProvider, out T). Otherwise append.
86+
var args = invocation.ArgumentList.Arguments;
87+
int insertAt = args.Count;
88+
if (args.Count > 0 && args[args.Count - 1].RefKindKeyword.IsKind(SyntaxKind.OutKeyword))
89+
insertAt = args.Count - 1;
90+
91+
var newArgs = args.Insert(insertAt, newArg);
92+
var newInvocation = invocation.WithArgumentList(invocation.ArgumentList.WithArguments(newArgs));
8593
var newRoot = EnsureGlobalizationUsing(root).ReplaceNode(invocation, newInvocation);
8694
return document.WithSyntaxRoot(newRoot);
8795
}

tests/Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests/LuceneDev2xxx/TestLuceneDev2000_2001_2002_2004_AddInvariantCultureCodeFixProvider.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,44 @@ public class Sample
100100
};
101101
await test.RunAsync();
102102
}
103+
104+
[Test]
105+
public async Task DoubleTryParse_InsertsInvariantCultureBeforeOutArg()
106+
{
107+
// Regression: TryParse signature is (string, IFormatProvider, out T) — the provider
108+
// must be inserted BEFORE the trailing `out` parameter, not appended at the end.
109+
var testCode = @"
110+
public class Sample
111+
{
112+
public bool M() => double.TryParse(""1.5"", out _);
113+
}";
114+
115+
var fixedCode = @"using System.Globalization;
116+
117+
public class Sample
118+
{
119+
public bool M() => double.TryParse(""1.5"", CultureInfo.InvariantCulture, out _);
120+
}";
121+
122+
var expected = new DiagnosticResult(Descriptors.LuceneDev2000_BclNumericParseMissingFormatProvider)
123+
.WithSeverity(DiagnosticSeverity.Warning)
124+
.WithMessageFormat(Descriptors.LuceneDev2000_BclNumericParseMissingFormatProvider.MessageFormat)
125+
.WithArguments("TryParse", "Double")
126+
.WithLocation("/0/Test0.cs", line: 4, column: 31);
127+
128+
var test = new InjectableCodeFixTest(
129+
() => new LuceneDev2000_BclNumericParseAnalyzer(),
130+
() => new LuceneDev2000_2001_2002_2004_AddInvariantCultureCodeFixProvider())
131+
{
132+
TestCode = testCode,
133+
FixedCode = fixedCode,
134+
ReferenceAssemblies = ReferenceAssemblies.Net.Net80,
135+
ExpectedDiagnostics = { expected },
136+
CodeActionEquivalenceKey = "Add CultureInfo.InvariantCulture",
137+
NumberOfIncrementalIterations = 2,
138+
NumberOfFixAllIterations = 2
139+
};
140+
await test.RunAsync();
141+
}
103142
}
104143
}

0 commit comments

Comments
 (0)