ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
preprocessor.module_rewrite_mixin.ModuleRewriteMixin Class Reference
Inheritance diagram for preprocessor.module_rewrite_mixin.ModuleRewriteMixin:
[legend]

Public Member Functions

 apply_range_rewrites (self, module_node, alias_seed=frozenset(), wrapper_seed=None)
 prepare_module (self, node, alias_seed=frozenset(), wrapper_seed=None, entry=False)

Static Public Member Functions

 collect_range_aliases (module_node, seed=frozenset())
 collect_range_wrappers (module_node)

Public Attributes

 module_name
 fixed_receivers
 referenced_names = _referenced_names(node)
 variable_names = self._variable_names(node)
 scope_binding_counts = self._scope_binding_counts(node)
 iterator_classes = self._scan_iterator_classes(node)
 iterator_params = self._scan_iterator_params(node)
 module_class_names
 instance_var_classes
 attr_list_element_classes = self._scan_attr_list_element_classes(node)
 list_var_element_classes = self._scan_list_var_element_classes(node)
 body
 bases
dict imported_module_names = {m for m in imports if imports.count(m) == 1} - others

Static Public Attributes

list module_dunder_all | None

Protected Member Functions

 _iter_module_scope (cls, root, shadow_names)
 _collect_module_const_ints (self, module_node)
 _fold_module_const_range_args (self, module_node)
 _rewrite_range_aliases (self, module_node, seed=frozenset())
 _collect_param_subscripting_funcs (self, module_node)
 _inline_range_wrappers (self, module_node, seed=None)
 _rewrite_module_aliases (self, module_node)
 _scan_iterator_classes (self, node)
 _scan_iterator_params (self, node)
 _iterator_params_of (self, func, calls)
 _is_iterator_construction (self, expr)
 _scan_dict_literal_bindings_and_calls (self, node)
 _scan_imported_module_names (self, node)
 _scan_shadowed_nondet_collections (self, node)
 _collect_scope_dict_binds (self, stmts)
 _record_scope_calls (self, stmts, local_binds, local_names, module_binds)

Static Protected Member Functions

 _target_names (target)
 _rebound_module_names (module_node)
 _bound_names_of (node)
 _scope_locally_binds (scope_node, names)
 _int_literal_value (node)
 _simple_single_return_defs (module_node)
 _collect_single_return_funcs (module_node)
 _capture_dunder_all (module_node)
 _binding_sites (module_node)
 _appears_before (module_node, name, stmt)
 _has_iter (cls, iterable)
 _names_bound_without_import (n)
 _walk_scope (stmts)

Protected Attributes

 _names_bound_by
 _next_unpack_tmp_id
 _single_return_funcs = self._collect_single_return_funcs(node)
 _param_subscripting_funcs = self._collect_param_subscripting_funcs(node)
dict _dict_param_call_shapes = {}

Member Function Documentation

◆ _appears_before()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._appears_before ( module_node,
name,
stmt )
staticprotected
Whether a Name *name* occurs in *module_node* before *stmt*.

◆ _binding_sites()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._binding_sites ( module_node)
staticprotected
How many places anywhere in *module_node* bind or declare each name.

◆ _bound_names_of()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._bound_names_of ( node)
staticprotected
Names a single statement/expression node binds in its own scope.

◆ _capture_dunder_all()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._capture_dunder_all ( module_node)
staticprotected
Return the literal list/tuple of names assigned to __all__.

◆ _collect_module_const_ints()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._collect_module_const_ints ( self,
module_node )
protected
Names bound exactly once, unconditionally at module top level, to an
integer literal, and never rebound — genuine module constants.

``_rebound_module_names`` already flags names assigned more than once,
assigned inside any conditional/loop/``with``, or declared ``global``,
so excluding it leaves only names that hold one fixed integer on every
path. Comprehension / generator-expression loop targets are a separate
local scope that ``_rebound_module_names`` does not see, so they are
excluded explicitly: a same-named module constant must never be folded
into ``[... range(N) ... for N in ...]``, where ``N`` is the loop
variable, not the constant.

◆ _collect_param_subscripting_funcs()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._collect_param_subscripting_funcs ( self,
module_node )
protected
Names that may index the first argument they are called with.

Covers defs whose body subscripts their first parameter, plus every
imported name, whose body this scan cannot see. Keyed on name alone, so
a nested or rebound def of the same name counts too: over-refusing
costs a clear error, under-refusing costs a verdict.

◆ _collect_scope_dict_binds()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._collect_scope_dict_binds ( self,
stmts )
protected
Map names bound to a dict literal in this scope to their dict[K, V]
annotation. A name reassigned to a conflicting shape or to a non-dict is
poisoned (dropped) so it is never used as recovery evidence. Returns
(bindings, all-assigned-names).

◆ _collect_single_return_funcs()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._collect_single_return_funcs ( module_node)
staticprotected
One-parameter single-return defs as name -> (param, expr), so a
``key=f`` folds like a lambda.

◆ _fold_module_const_range_args()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._fold_module_const_range_args ( self,
module_node )
protected
Replace module-constant ``Name`` args of ``range()`` calls with their
integer literals.

``list(range(N))`` with a constant ``N`` otherwise takes the *symbolic*
range path, which builds a list whose ``size`` is set but whose elements
are nondet garbage — reading/slicing/copying it raises a spurious
``dereference failure`` (an unsound false positive). Folding a genuine
constant so the *concrete* range path materialises real elements removes
the false alarm. ``_iter_module_scope`` skips any nested function/class
scope that locally rebinds the name, so a shadowing parameter/local is
never folded to the module constant.

Only ``list(range(...))`` / ``tuple(range(...))`` — the sequence
*materialisation* contexts where the false deref occurs — are folded. A
``range()`` used directly as a ``for`` iterable is left untouched: it
never materialises elements, and its lowering models a zero ``step`` as
a runtime ``step != 0`` assertion that folding to a literal would turn
into a preprocess-time error (regression/python/range23_fail).

◆ _has_iter()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._has_iter ( cls,
iterable )
staticprotected

◆ _inline_range_wrappers()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._inline_range_wrappers ( self,
module_node,
seed = None )
protected
Inline trivial def f(p): return range(p_or_const, ...) wrappers.

◆ _int_literal_value()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._int_literal_value ( node)
staticprotected
Int value of an integer-literal AST node (or unary +/- of one), else
None. Booleans are excluded — ``True``/``False`` are not range sizes.

◆ _is_iterator_construction()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._is_iterator_construction ( self,
expr )
protected

◆ _iter_module_scope()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._iter_module_scope ( cls,
root,
shadow_names )
protected
Yield descendants of *root* whose enclosing scope is the module.

◆ _iterator_params_of()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._iterator_params_of ( self,
func,
calls )
protected
The plain positional parameters of `func` that each of `calls`
passes positionally as a `Cls(...)` of an iterator class.

◆ _names_bound_without_import()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._names_bound_without_import ( n)
staticprotected
Names `n` binds in its scope, for any node but an `import`.

◆ _rebound_module_names()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._rebound_module_names ( module_node)
staticprotected
Module-top names that may be rebound after their first binding.

◆ _record_scope_calls()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._record_scope_calls ( self,
stmts,
local_binds,
local_names,
module_binds )
protected
Record the per-call positional dict shapes for every direct call in
this scope, resolving Name arguments against the local bindings (or the
module bindings for free names).

◆ _rewrite_module_aliases()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._rewrite_module_aliases ( self,
module_node )
protected
Rewrite a top-level `alias = mod` into `import <module> as alias`.

Only when `mod` is bound solely by an earlier top-level import, `alias`
solely by this statement, and nothing reads `alias` before it: then
both forms bind the same module at the same point, and the converter
resolves calls through the import form only (#8366).

◆ _rewrite_range_aliases()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._rewrite_range_aliases ( self,
module_node,
seed = frozenset() )
protected
Rewrite module-scope alias = range (and chains) to canonical range.

◆ _scan_dict_literal_bindings_and_calls()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._scan_dict_literal_bindings_and_calls ( self,
node )
protected
Collect evidence for parameter-dict element recovery (#5444).

For each scope (the module body and every function body, independently)
records its dict-literal name bindings, then resolves each direct
``name(...)`` call's positional arguments against that scope's bindings
(falling back to the module scope for free names). The result maps a
function name to its per-call list of argument dict[K, V] shapes, which
_recover_param_dict_annotation collapses only when every call agrees —
keeping the inference sound and scope-correct (a function-local dict
never poisons a same-named module global).

◆ _scan_imported_module_names()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._scan_imported_module_names ( self,
node )
protected
Record names bound by a module-level `import` and by nothing else.

Only such a name denotes the module wherever it is read, so only its
attributes may stand for the module's nondet functions.

◆ _scan_iterator_classes()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._scan_iterator_classes ( self,
node )
protected
Classes whose instances a for loop iterates through `__iter__`, for visit_For.

A class qualifies when it defines `__iter__` or inherits it from a
module class that does. A class without `__iter__` is not iterable,
and CPython's TypeError for it is already reported. The class name
must be bound only by its class statement, so a call of it constructs
the class.

◆ _scan_iterator_params()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._scan_iterator_params ( self,
node )
protected
`(id(def), param)` for each parameter of a module function that
every reference to the function passes a `Cls(...)` of an iterator
class, so a for loop over the parameter can use `__iter__` (#8628).

The function name must be bound once and only ever called directly,
so no call goes unseen.

◆ _scan_shadowed_nondet_collections()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._scan_shadowed_nondet_collections ( self,
node )
protected
Record `nondet_list`/`nondet_dict` names this module defines itself.

The rewrite to a typed builder matches on the callee name, so without
this a user's own `def nondet_list(...)` would be replaced by ESBMC's
model and its body never verified. A name that is only *imported* stays
interceptable: SV-COMP harnesses import `_sv_verifier.nondet_list`
expecting ESBMC's model, not the stub's body.

◆ _scope_locally_binds()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._scope_locally_binds ( scope_node,
names )
staticprotected
True iff any of *names* is locally bound inside *scope_node*.

◆ _simple_single_return_defs()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._simple_single_return_defs ( module_node)
staticprotected
Yield ``(stmt, params, expr)`` for each undecorated, never-rebound
module-level ``def f(p, ...): return <expr>`` with plain parameters.

◆ _target_names()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._target_names ( target)
staticprotected
Names bound by an assignment target, including tuple/list unpacking.

◆ _walk_scope()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._walk_scope ( stmts)
staticprotected
Yield AST nodes within ``stmts`` without crossing into a nested
function/class/lambda scope (which binds its own names).

◆ apply_range_rewrites()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.apply_range_rewrites ( self,
module_node,
alias_seed = frozenset(),
wrapper_seed = None )
Run the range-alias and range-wrapper rewrites on *module_node*.

◆ collect_range_aliases()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.collect_range_aliases ( module_node,
seed = frozenset() )
static
Collect module-scope canonical-range aliases.

◆ collect_range_wrappers()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.collect_range_wrappers ( module_node)
static
Collect trivial def f(p): return range(...) wrappers at module scope.

◆ prepare_module()

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.prepare_module ( self,
node,
alias_seed = frozenset(),
wrapper_seed = None,
entry = False )
Run pre-visit analyses and range-alias/wrapper canonicalization.

`entry` marks the program itself, whose module-level names no other
module imports.

Member Data Documentation

◆ _dict_param_call_shapes

dict preprocessor.module_rewrite_mixin.ModuleRewriteMixin._dict_param_call_shapes = {}
protected

◆ _names_bound_by

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._names_bound_by
protected

◆ _next_unpack_tmp_id

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._next_unpack_tmp_id
protected

◆ _param_subscripting_funcs

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._param_subscripting_funcs = self._collect_param_subscripting_funcs(node)
protected

◆ _single_return_funcs

preprocessor.module_rewrite_mixin.ModuleRewriteMixin._single_return_funcs = self._collect_single_return_funcs(node)
protected

◆ attr_list_element_classes

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.attr_list_element_classes = self._scan_attr_list_element_classes(node)

◆ bases

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.bases

◆ body

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.body

◆ fixed_receivers

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.fixed_receivers

◆ imported_module_names

dict preprocessor.module_rewrite_mixin.ModuleRewriteMixin.imported_module_names = {m for m in imports if imports.count(m) == 1} - others

◆ instance_var_classes

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.instance_var_classes
Initial value:
= \
self._build_var_class_map(node)

◆ iterator_classes

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.iterator_classes = self._scan_iterator_classes(node)

◆ iterator_params

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.iterator_params = self._scan_iterator_params(node)

◆ list_var_element_classes

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.list_var_element_classes = self._scan_list_var_element_classes(node)

◆ module_class_names

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.module_class_names

◆ module_dunder_all

list preprocessor.module_rewrite_mixin.ModuleRewriteMixin.module_dunder_all | None
static

◆ module_name

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.module_name

◆ referenced_names

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.referenced_names = _referenced_names(node)

◆ scope_binding_counts

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.scope_binding_counts = self._scope_binding_counts(node)

◆ variable_names

preprocessor.module_rewrite_mixin.ModuleRewriteMixin.variable_names = self._variable_names(node)

The documentation for this class was generated from the following file: