Skip to content

Implement LuceneDev2000-2008 numeric culture analyzers (apache/lucenenet#924)#28

Merged
paulirwin merged 6 commits intoapache:mainfrom
paulirwin:issue/924
Apr 30, 2026
Merged

Implement LuceneDev2000-2008 numeric culture analyzers (apache/lucenenet#924)#28
paulirwin merged 6 commits intoapache:mainfrom
paulirwin:issue/924

Conversation

@paulirwin
Copy link
Copy Markdown
Contributor

@paulirwin paulirwin commented Apr 26, 2026

Summary

  • Adds nine analyzers under a new Globalization category (LuceneDev2000-LuceneDev2008) that flag culture-sensitive numeric format/parse calls so the Lucene.NET team can audit each call site against Java Lucene's invariant-culture default. Create Roslyn code analyzer to streamline review of proper usage of format/parse methods for numeric types lucenenet#924.
  • Adds three accompanying CodeFixProviders that offer one-click fixes to add CultureInfo.InvariantCulture (or CurrentCulture) at the call site and a shared NumericTypeHelper utility for BCL/J2N numeric type detection.
  • Adds J2N 2.1.0 to centrally-managed packages and references it from the Sample and test projects so the J2N analyzer (2004) can be exercised end-to-end.

Diagnostic IDs

ID Default Severity Enabled by default Bucket
LuceneDev2000 Warning Yes BCL Parse/TryParse without IFormatProvider
LuceneDev2001 Warning Yes BCL ToString/TryFormat without IFormatProvider (exempts ToString() overrides)
LuceneDev2002 Warning Yes Convert.ToXxx/Convert.ToString numeric without IFormatProvider
LuceneDev2003 Warning Yes string.Format with numeric arg, no IFormatProvider
LuceneDev2004 Warning Yes J2N Numerics.* without IFormatProvider
LuceneDev2005 Warning Yes Implicit numeric formatting via string concatenation ("" + i)
LuceneDev2006 Warning Yes Implicit numeric formatting via string interpolation ($"{i}"); skips FormattableString.Invariant and string.Create(InvariantCulture, ...)
LuceneDev2007 Warning Yes Explicit IFormatProvider, but not InvariantCulture
LuceneDev2008 Info No (off by default) Explicit CultureInfo.InvariantCulture (review-sweep aid; enable during the audit)

Notes

  • IDs reserved on main in commit 68a5922 (separate per-repo policy).
  • 180 tests pass (137 analyzer + 43 codefix); zero analyzer warnings on the analyzer projects themselves.
  • J2N 2.1.0 confirmed to ship TryFormat overloads on the J2N.Numerics.* types — all of them already require IFormatProvider, so they belong in the explicit-culture review aid (2007/2008), not the missing-provider bucket.

🤖 Generated with Claude Code

paulirwin and others added 2 commits April 26, 2026 14:19
Adds nine Roslyn analyzers under the new Globalization category that
flag culture-sensitive numeric format/parse calls so the Lucene.NET
team can audit each one against Java Lucene's invariant-culture default:

- 2000: BCL Parse/TryParse without IFormatProvider
- 2001: BCL ToString/TryFormat without IFormatProvider (exempts
  ToString() overrides)
- 2002: Convert.ToXxx / Convert.ToString numeric without IFormatProvider
- 2003: string.Format with numeric arg, no IFormatProvider
- 2004: J2N.Numerics.* without IFormatProvider
- 2005: implicit numeric formatting via string concatenation
- 2006: implicit numeric formatting via string interpolation
  (skips FormattableString.Invariant and string.Create with
  InvariantCulture)
- 2007: explicit IFormatProvider, but not InvariantCulture
- 2008: explicit InvariantCulture (review-sweep aid; off by default)

Also adds three CodeFixProviders covering 2000/2001/2002/2004,
2003, and 2005/2006, and a NumericTypeHelper utility shared by the
analyzers.

Sample project gets a violation file plus a J2N package reference.
Tests cover positive and negative paths for all analyzers and the
codefix outputs (180 tests total, all passing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new set of Roslyn analyzers/code fixes under the Globalization category (LuceneDev2000LuceneDev2008) to detect culture-sensitive numeric parse/format patterns (including BCL, System.Convert, string.Format, and selected J2N.Numerics.*) and provide one-click remediations that make the culture explicit.

Changes:

  • Introduces analyzers LuceneDev2000LuceneDev2008 plus shared utilities (NumericTypeHelper) and descriptors/resources for titles/messages.
  • Adds code fix providers to insert CultureInfo.InvariantCulture/CurrentCulture or wrap implicit formatting with .ToString(...).
  • Adds end-to-end samples and test coverage, including referencing J2N (2.1.0) from centrally-managed packages.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2000_BclNumericParseAnalyzer.cs Adds analyzer tests for BCL numeric Parse/TryParse missing IFormatProvider.
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2001_BclNumericToStringAnalyzer.cs Adds analyzer tests for numeric ToString (and intended TryFormat) missing IFormatProvider.
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2002_ConvertNumericAnalyzer.cs Adds analyzer tests for System.Convert numeric conversions missing IFormatProvider.
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2003_StringFormatNumericAnalyzer.cs Adds analyzer tests for string.Format with numeric args missing IFormatProvider.
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2004_J2NNumericMissingFormatProviderAnalyzer.cs Adds analyzer tests for J2N.Numerics.* calls missing IFormatProvider.
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2005_NumericConcatenationAnalyzer.cs Adds analyzer tests for implicit numeric formatting via string concatenation.
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2006_NumericInterpolationAnalyzer.cs Adds analyzer tests for implicit numeric formatting via interpolation (with invariant-context exemptions).
tests/Lucene.Net.CodeAnalysis.Dev.Tests/LuceneDev2xxx/TestLuceneDev2007_2008_NumericExplicitCultureAnalyzer.cs Adds analyzer tests for explicit format providers (non-invariant vs invariant review aid).
tests/Lucene.Net.CodeAnalysis.Dev.Tests/Lucene.Net.CodeAnalysis.Dev.Tests.csproj References J2N to support analyzer tests that load J2N metadata.
tests/Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests/LuceneDev2xxx/TestLuceneDev2000_2001_2002_2004_AddInvariantCultureCodeFixProvider.cs Adds code fix tests for appending culture arguments to supported APIs.
tests/Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests/LuceneDev2xxx/TestLuceneDev2003_AddInvariantCultureToStringFormatCodeFixProvider.cs Adds code fix tests for inserting culture provider into string.Format.
tests/Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests/LuceneDev2xxx/TestLuceneDev2005_2006_WrapNumericWithInvariantCodeFixProvider.cs Adds code fix tests for wrapping implicit formatting in .ToString(CultureInfo...).
tests/Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests/Lucene.Net.CodeAnalysis.Dev.CodeFixes.Tests.csproj References J2N for code fix test compilation.
src/Lucene.Net.CodeAnalysis.Dev/Utility/NumericTypeHelper.cs Introduces shared helpers for numeric type detection, format-provider detection, and invariant-context checks.
src/Lucene.Net.CodeAnalysis.Dev/Utility/Descriptors.LuceneDev2xxx.cs Adds descriptors for LuceneDev2000LuceneDev2008.
src/Lucene.Net.CodeAnalysis.Dev/Resources.resx Adds localized titles/descriptions/messages for 2000–2008 diagnostics.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2000_BclNumericParseAnalyzer.cs Implements analyzer for missing IFormatProvider on numeric Parse/TryParse.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2001_BclNumericToStringAnalyzer.cs Implements analyzer for missing IFormatProvider on numeric ToString/TryFormat.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2002_ConvertNumericAnalyzer.cs Implements analyzer for System.Convert numeric conversions missing IFormatProvider.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2003_StringFormatNumericAnalyzer.cs Implements analyzer for string.Format numeric formatting missing IFormatProvider.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2004_J2NNumericMissingFormatProviderAnalyzer.cs Implements analyzer for selected J2N.Numerics.* calls missing IFormatProvider.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2005_NumericConcatenationAnalyzer.cs Implements analyzer for culture-sensitive implicit formatting via concatenation.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2006_NumericInterpolationAnalyzer.cs Implements analyzer for culture-sensitive implicit formatting via interpolation.
src/Lucene.Net.CodeAnalysis.Dev/LuceneDev2xxx/LuceneDev2007_2008_NumericExplicitCultureAnalyzer.cs Implements analyzers for explicit providers (non-invariant warning + invariant review aid).
src/Lucene.Net.CodeAnalysis.Dev/AnalyzerReleases.Unshipped.md Registers new diagnostic IDs and release notes.
src/Lucene.Net.CodeAnalysis.Dev.Sample/LuceneDev2xxx/LuceneDev2000_2008_NumericCultureSample.cs Adds sample call sites to exercise all diagnostics.
src/Lucene.Net.CodeAnalysis.Dev.Sample/Lucene.Net.CodeAnalysis.Dev.Sample.csproj References J2N so the sample can exercise J2N-related diagnostics.
src/Lucene.Net.CodeAnalysis.Dev.CodeFixes/LuceneDev2xxx/LuceneDev2000_2001_2002_2004_AddInvariantCultureCodeFixProvider.cs Adds code fix provider to append culture argument to supported APIs + ensures globalization using.
src/Lucene.Net.CodeAnalysis.Dev.CodeFixes/LuceneDev2xxx/LuceneDev2003_AddInvariantCultureToStringFormatCodeFixProvider.cs Adds code fix provider to insert culture provider as first argument to string.Format.
src/Lucene.Net.CodeAnalysis.Dev.CodeFixes/LuceneDev2xxx/LuceneDev2005_2006_WrapNumericWithInvariantCodeFixProvider.cs Adds code fix provider to wrap expressions in .ToString(CultureInfo...).
Directory.Packages.props Adds centrally-managed J2N package version (2.1.0).
DiagnosticCategoryAndIdRanges.txt Reserves/records the Globalization diagnostic range LuceneDev2000LuceneDev2008.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Lucene.Net.CodeAnalysis.Dev/Utility/NumericTypeHelper.cs
Comment thread src/Lucene.Net.CodeAnalysis.Dev/Utility/NumericTypeHelper.cs
paulirwin and others added 4 commits April 26, 2026 15:02
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>
The codefix hardcoded `\n` for the inserted `using System.Globalization;`
directive, which mismatched documents using CRLF (the .gitattributes
policy for *.cs files in this repo). CI checks out CRLF; local Mac
checkouts had LF, so tests passed locally but failed on CI.

Detect the document's existing line ending from its SourceText and emit
the same. Adds a regression test that exercises a CRLF-encoded source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three fixes from PR apache#28 review:

1. LuceneDev2001 missed `int.TryFormat(buffer, out _)` because the
   resolved overload declares an *optional* IFormatProvider parameter,
   and the analyzer bailed whenever the signature had one. Switch to
   checking whether the invocation actually supplies a provider arg.

2. NumericTypeHelper.GetFormatProviderArgument returned null for `null`
   literal arguments because GetTypeInfo(...).Type is null for them,
   so calls like `i.ToString((string)null, null)` slipped past the
   2007/2008 explicit-culture analyzer. Fall back to ConvertedType so
   overload-resolution-chosen parameter types are picked up.

3. Stale comment in LuceneDev2003 claimed using-static forms aren't
   handled, but the implementation already supports IdentifierNameSyntax
   and verifies the containing type is System.String. Comment updated.

Adds three regression tests covering each fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address Copilot review: GetJ2NNumericTypes was calling
GetTypeByMetadataName for all 7 J2N numeric types on every numeric
invocation/concat/interpolation node visited. The result is identical
for the lifetime of a Compilation, so cache it in a
ConditionalWeakTable keyed by Compilation.

Also short-circuits IsJ2NNumericType: BCL primitives never live under
J2N.Numerics, so checking the containing namespace's display string up
front avoids the symbol-equality loop entirely on the hottest path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@paulirwin paulirwin marked this pull request as ready for review April 29, 2026 13:01
@paulirwin paulirwin merged commit 14d3556 into apache:main Apr 30, 2026
8 checks passed
@paulirwin paulirwin deleted the issue/924 branch April 30, 2026 21:11
Comment thread Directory.Packages.props
@paulirwin paulirwin added the notes:new-feature A new feature label May 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

notes:new-feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants