nullflow

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 11, 2026 License: MIT Imports: 4 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConditionFalseProvesNonNull

func ConditionFalseProvesNonNull(file *scanner.File, cond, receiver, useIdx uint32) bool

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

func ConditionFalseProvesNull(file *scanner.File, cond, receiver, useIdx uint32) bool

ConditionFalseProvesNull is the dual of ConditionFalseProvesNonNull.

func ConditionTrueProvesNonNull

func ConditionTrueProvesNonNull(file *scanner.File, cond, receiver, useIdx uint32) bool

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

func ConditionTrueProvesNull(file *scanner.File, cond, receiver, useIdx uint32) bool

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

func IsGuardedNonNull(file *scanner.File, useIdx uint32, receiver uint32) bool

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

func IsInsideContainsKeyFilterChain(file *scanner.File, useIdx uint32, receiver uint32) bool

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

func IsMapContainsKeyGuarded(file *scanner.File, useIdx uint32, receiver, key uint32) bool

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

func IsPostFilterSmartCast(file *scanner.File, useIdx uint32, receiverText string) bool

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

func IsShortCircuitGuardedNonNull(file *scanner.File, useIdx uint32, receiver uint32) bool

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

func ResolveSimpleReferenceDeclaration(file *scanner.File, ref uint32) uint32

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

type ReferencePath struct {
	Parts []string
	Nodes []uint32
	Root  uint32
}

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.).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL