C#: Bugfix for nullguards for complex patterns.#20449
C#: Bugfix for nullguards for complex patterns.#20449aschackmull merged 3 commits intogithub:mainfrom
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR fixes a bug in the C# code analysis library where pattern matching expressions were incorrectly identifying null guards in the wrong branches. The fix addresses complex patterns like x is (string or null) and x is not string that were being analyzed incorrectly.
Key changes:
- Introduces a new helper function
patternContainsNullto properly evaluate whether a pattern matches null values - Replaces simple null literal checks with comprehensive pattern analysis that handles complex nested patterns
- Fixes the logic for determining which branch represents a null guard condition
michaelnebel
left a comment
There was a problem hiding this comment.
Thank you for doing this!
- Added some questions/comments.
- It looks like some tests are failing.
- We should probably run DCA.
| private import AbstractValues | ||
|
|
||
| /** Gets the value resulting from matching `null` against `pat`. */ | ||
| private boolean patternContainsNull(PatternExpr pat) { |
There was a problem hiding this comment.
The name might be a bit misleading at the pattern can have "mentions" (and thus containing) null without matching null. Maybe rename to matchesNull.
There was a problem hiding this comment.
Yeah, I was thinking "contains" in the sense that the pattern represents a set of values. But yes, I'll change it, patternMatchesNull is better.
| // E.g. `x is string` or `x is ""` | ||
| not pm.getPattern() instanceof NullLiteral and | ||
| branch = true and | ||
| branch.booleanNot() = patternContainsNull(pm.getPattern()) and |
There was a problem hiding this comment.
Maybe consider elaborating the comment above.
Do we need the dual
// E.g. `x is null` or `x is null or ...`
branch = patternContainsNull(pm.getPattern()) and
isNull = true
There was a problem hiding this comment.
No. Just because a pattern will match null doesn't mean that it's the only value that it'll match, so we can't conclude that the value is null based on a match or no-match branch edge (unless the pattern is literally null). I guess we could add another case for x is not null, which does imply x == null in its false branch, but I think I'll postpone that particular tweak to my work on instantiating Guards, because then we can handle those cases in slightly more generality.
There was a problem hiding this comment.
Ah yes, that is of course correct.
There is some overlap in this disjunct with
// E.g. `x is null`
pm.getPattern() instanceof NullLiteral and
isNull = branch
should the above be changed to only handle isNull = branch = true as a special case?
There was a problem hiding this comment.
True, but probably doesn't matter. Regardless, this is just a stepping stone - I'm working on a shared Guards instantiation in a separate branch where this will be tweaked anyway.
There was a problem hiding this comment.
Excellent! Once again, thank you!
Already done, we get some nice FP reduction. I'll add a change note describing that. |
Patterns like
x is (string or null)andx is not stringwere being identified as null guards in the wrong branch.