fix: resolve SonarCloud reliability regression (A→B) from nullable-references PR - #656
Merged
Conversation
…es PR PR #642 touched two public readonly array field declarations (adding `?` annotations) without changing their design, which caused SonarCloud to flag S3887 ("non-private readonly field exposes mutable array") as new Bug-type issues on both lines, dropping the reliability rating from A to B. - Closure.A: made internal, since Closure's constructor is already internal and the field is unreachable by external consumers. Added InternalsVisibleTo("Handlebars.Test") for the one test that reads it directly, and pass BindingFlags.NonPublic to the reflection GetField call that resolves this field for compiled closure expressions. - PathInfo.Segments: left public with a NOSONAR suppression instead, since PathInfo instances do reach public surfaces (HelperOptions, PathExpression, etc.) and the field has been public since 2020 - flipping it to internal would be a real breaking change.
rexm
enabled auto-merge
August 6, 2026 01:38
rexm
disabled auto-merge
August 6, 2026 01:38
Making Closure.A internal required BindingFlags.NonPublic on the reflection
GetField("A") lookup used to build compiled closure expressions. SonarCloud
flagged that explicit accessibility bypass as S3011 (MAJOR), which dropped
Maintainability Rating on New Code to C and failed the Quality Gate.
Closure's constructor is already internal, so A was never reachable by
external consumers anyway - reverting to public (with NOSONAR, matching
the treatment already given to PathInfo.Segments) removes the smell
without any real encapsulation loss, and drops the now-unnecessary
InternalsVisibleTo attribute.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
SonarCloud's reliability rating dropped from A to B at the analysis of the PR #642 ("Nullable Reference Types") merge commit. The Quality Gate event was
Red (was Green)/ "Reliability Rating on New Code > 1".Root cause: PR #642 added
?nullable annotations to two public readonly array field declarations without otherwise changing them. Touching those lines caused SonarCloud to (re-)surface a pre-existing mutable-array-exposure smell (csharpsquid:S3887, "Use an immutable collection or reduce the accessibility of the non-private readonly field") as fresh Bug-type issues:source/Handlebars/Compiler/ClosureBuilder.cs:163—Closure.Asource/Handlebars/PathStructure/PathInfo.cs:108—PathInfo.SegmentsBoth fields already existed as public arrays before #642; only the reliability-rule bookkeeping was reset by that PR's diff.
Changes
Closure.A→ madeinternal. Safe:Closure's constructor is alreadyinternal, so no external consumer can ever obtain an instance to read this field. AddedInternalsVisibleTo("Handlebars.Test")(newsource/Handlebars/Properties/AssemblyInfo.cs) sinceClosureBuilderTests.csreads it directly, and updated the oneType.GetField("A")reflection call inClosureBuilder.csto passBindingFlags.NonPublic | BindingFlags.Instance(defaultGetFieldonly resolves public members).PathInfo.Segments→ left public with a// NOSONARsuppression instead of changing accessibility.PathInfoinstances flow through public surfaces (HelperOptions,PathExpression, etc.) and this field has been public since 2020 (pre-1.0), well before the current2.3.0release line — flipping it tointernalwould be a real breaking change for any consumer reflecting on or compiling against it directly.Test plan
dotnet build Handlebars.sln -c Release— succeeds, no new warnings from this changedotnet test --filter "FullyQualifiedName~ClosureBuilderTests|FullyQualifiedName~PathInfoTests"— 19/19 pass (exercisesClosure.AandPathInfo.Segmentsdirectly)dotnet test Handlebars.sln -c Release— full suite, 1867/1867 pass