Documentation
¶
Overview ¶
Package nullflow provides flow-sensitive nullability analysis primitives over a parsed scanner.File. It owns the proofs that a given use site is non-null via guards, early-return, short-circuit, same-block assignment, post-filter smart casts, contains-key checks, and explicit-this reference matching.
Rules consume nullflow.* APIs instead of open-coding the same flat-AST walks. The package depends only on the scanner package; it does not import the rules package and must not.
Index ¶
- func ConditionFalseProvesNonNull(file *scanner.File, cond, receiver, useIdx uint32) bool
- func ConditionFalseProvesNull(file *scanner.File, cond, receiver, useIdx uint32) bool
- func ConditionTrueProvesNonNull(file *scanner.File, cond, receiver, useIdx uint32) bool
- func ConditionTrueProvesNull(file *scanner.File, cond, receiver, useIdx uint32) bool
- func IsEarlyReturnGuarded(file *scanner.File, useIdx uint32, receiver uint32, ...) bool
- func IsEarlyReturnMapContainsKeyGuarded(file *scanner.File, useIdx uint32, receiver, key uint32, ...) bool
- func IsGuardedNonNull(file *scanner.File, useIdx uint32, receiver uint32) bool
- func IsInsideContainsKeyFilterChain(file *scanner.File, useIdx uint32, receiver uint32) bool
- func IsMapContainsKeyGuarded(file *scanner.File, useIdx uint32, receiver, key uint32) bool
- func IsPostFilterSmartCast(file *scanner.File, useIdx uint32, receiverText string) bool
- func IsSameBlockAssignedNonNullBeforeUse(file *scanner.File, useIdx uint32, receiver uint32, ...) bool
- func IsShortCircuitGuardedNonNull(file *scanner.File, useIdx uint32, receiver uint32) bool
- func ResolveSimpleReferenceDeclaration(file *scanner.File, ref uint32) uint32
- type ReferencePath
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ConditionFalseProvesNonNull ¶
ConditionFalseProvesNonNull reports whether asserting that `cond` is false proves that `receiver` is non-null at useIdx. Recognizes call-form null predicates like `isNullOrEmpty()` / `isNullOrBlank()` / `TextUtils.isEmpty()`.
func ConditionFalseProvesNull ¶
ConditionFalseProvesNull is the dual of ConditionFalseProvesNonNull.
func ConditionTrueProvesNonNull ¶
ConditionTrueProvesNonNull reports whether asserting that `cond` is true proves that `receiver` is non-null at useIdx. Handles equality checks (x != null), conjunction/disjunction normal forms, and `!`-negated forms. when_condition operands are recursed into.
func ConditionTrueProvesNull ¶
ConditionTrueProvesNull is the dual of ConditionTrueProvesNonNull.
func IsEarlyReturnGuarded ¶
func IsEarlyReturnGuarded( file *scanner.File, useIdx uint32, receiver uint32, bodyExits func(file *scanner.File, body uint32) bool, ) bool
IsEarlyReturnGuarded reports whether an `if (x == null) return` style early exit appears earlier in the same statements scope as useIdx, proving the receiver non-null. The bodyExits callback decides whether a control body always transfers control out of the function (return/throw/break/continue or a fully-covering nested if-else); nullflow does not own that CFG logic.
func IsEarlyReturnMapContainsKeyGuarded ¶
func IsEarlyReturnMapContainsKeyGuarded( file *scanner.File, useIdx uint32, receiver, key uint32, bodyExits func(file *scanner.File, body uint32) bool, ) bool
IsEarlyReturnMapContainsKeyGuarded reports whether useIdx is preceded in the same statements scope by an `if (!receiver.containsKey(key)) return` style guard. The bodyExits parameter is the caller-supplied predicate that decides whether a control_structure_body always transfers control out of the enclosing function (return, throw, break, continue, or a fully-covering nested if/else chain). nullflow does not own that decision because it lives outside null reasoning.
func IsGuardedNonNull ¶
IsGuardedNonNull reports whether useIdx sits in a control-flow region where the receiver expression is provably non-null via an enclosing if/when guard. Walks outward from useIdx, looking at each control_structure_body or when_entry to see if its condition proves the receiver non-null.
func IsInsideContainsKeyFilterChain ¶
IsInsideContainsKeyFilterChain reports whether useIdx is inside a transform lambda (.map / .forEach / .let / etc.) whose receiver chain has a preceding `.filter { receiver.containsKey(...) }` step. In that case any subsequent access on the same receiver inside the transform is provably non-null.
func IsMapContainsKeyGuarded ¶
IsMapContainsKeyGuarded reports whether useIdx sits inside a control flow branch dominated by a `receiver.containsKey(key)` check (or its negation in the else branch). The receiver and key nodes are matched structurally; both must be named flat-AST nodes from the same file.
func IsPostFilterSmartCast ¶
IsPostFilterSmartCast reports whether useIdx is inside a transform lambda (.map / .forEach / .let / .associate / etc.) preceded in the same chain by a `.filter { it.<field> != null }` (or `.filterNotNull()` for the bare `it` case). receiverText is the textual receiver under the bang — typically "it" or "it.<field>". When the predicate holds, a `!!` on that field is a smart-cast workaround rather than an unsafe assertion.
func IsSameBlockAssignedNonNullBeforeUse ¶
func IsSameBlockAssignedNonNullBeforeUse(file *scanner.File, useIdx uint32, receiver uint32, resolver typeinfer.TypeResolver) bool
IsSameBlockAssignedNonNullBeforeUse reports whether a simple-name receiver is provably non-null at useIdx because of an assignment earlier in the same statements block. Handles direct `x = nonNullValue` and `if (x == null) x = create()` shapes. The resolver, when supplied, is consulted to resolve the assignment RHS type; nil callers fall back to a purely structural heuristic.
func IsShortCircuitGuardedNonNull ¶
IsShortCircuitGuardedNonNull reports whether the receiver is proven non-null by a preceding operand of an enclosing conjunction_expression. This catches `x != null && x!!.y` patterns where the right-hand bang relies on the short-circuit evaluation of the left side.
func ResolveSimpleReferenceDeclaration ¶
ResolveSimpleReferenceDeclaration returns the flat-AST index of the declaration that ref textually resolves to in the same file, preferring nearer local declarations over class members. Returns 0 when no candidate is visible. Cross-file resolution is out of scope; callers needing more precise resolution should use the typeinfer.Resolver.
Types ¶
type ReferencePath ¶
ReferencePath is a textual+positional decomposition of a navigation chain expression like `a.b.c` or `this.a.b`. Parts holds the dotted text segments; Nodes holds the flat-AST node indexes for each segment; Root is the first node in the chain (the leftmost identifier or this_expression).
func FlatReferencePathFromExpr ¶
func FlatReferencePathFromExpr(file *scanner.File, idx uint32) (ReferencePath, bool)
FlatReferencePathFromExpr decomposes a simple_identifier, this_expression, or navigation_expression into a ReferencePath. Returns ok=false for any other shape (call expressions, indexing expressions, etc.).