Add opt-in InputSig2 predicates to support a function-exit epilogue whose
placement depends on reachability (such as Go's deferred calls, run at
exit in last-in-first-out order):
- deferExitStep: language-provided exit-epilogue edges, wired into
explicitStep but excluded from the defer-free reachability.
- overridesCallableBodyExit: suppresses the default fall-through edge from
a body's "after" node to the normal exit, so the epilogue can be
interposed on fall-through paths.
To let a language compute the reachability gate for those edges without
observing them (and without a non-monotonic cycle through reachable):
- explicitStep is split into explicitStepCommon (defer-free) plus
deferExitStep, and defaultCfg now negates explicitStepCommon so default
evaluation does not depend on deferExitStep.
- succIgnoringDeferExit exposes the defer-free successor relation, typed
over PreControlFlowNode so it does not depend on reachable.
- getASuccessorIgnoringDeferredExit exposes the same relation as a
ControlFlowNode member for general use.
- isInOrderNode exposes a structural, reachability-free node-identity test
for use inside the negations a language needs when computing its gate.
- EntryNodeImpl is no longer private, so a language can identify the entry
node over PreControlFlowNode.
All InputSig2 additions default to none(), leaving other languages
unchanged.
To determine that test9 can't return normally, you have to use the fact
that test5 can't return normally. This would make CFG construction
recursive, which would be bad for performance. Therefore we accept the
limitation that we cannot detect that test9 can't return normally, and
we change the test output.
Follow-up to the getAFlowNode deprecation in the same PR: same AST→legacy-CFG
bridge pattern. The 11 internal call sites (across objects/, types/,
frameworks/, and TypeTrackingImpl) are rewritten to bind a `Return ret`
explicitly, then constrain via `ret.getScope() = f and n.getNode() = ret.getValue()`.
The predicate itself is preserved with a deprecation note so external
users do not experience churn.
Semantic noop.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preparatory refactor for the shared-CFG dataflow migration.
Deprecates the AstNode.getAFlowNode() cached predicate on the public
Python QL API and rewrites all ~140 internal callers across lib/, src/,
test/, and tools/ from `expr.getAFlowNode() = cfgNode` to
`cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which
already exists in Flow.qll.
The predicate itself is preserved (with a deprecation note pointing at
the new pattern) so external users do not experience churn — they can
migrate at their own pace and the AST/CFG hierarchies still get the
intended untangling once the deprecation eventually elapses.
Semantic noop verified by:
- All 361 lib/ + src/ queries compile clean.
- All 122 ControlFlow + PointsTo library-tests pass.
- All 64 dataflow library-tests pass.
- All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/
Security/CWE-798/ModificationOfParameterWithDefault query-tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>