classBackwardSlicer
final class BackwardSlicer
Walks back from a call to the start of its body, keeping only what its argument depends on.
The walk starts with the names the argument reads and goes back statement by statement. An assignment to one of those names is kept as a step, and the names its right-hand side reads are looked for instead. A branch that assigns none of them is stepped over whole; one that does splits the path into one path per arm, which is what keeps the values an arm assigns together. A loop becomes one path per number of passes, up to the budget's limit. What comes out at the start of the body is the set of paths, each with the steps that lead from there to the call and the names still left to find.
Constants§
public const MAX_PATHS = 24How many paths are kept apart before the rest are gathered into one.
Methods§
public function __construct(
SourceTree $tree,
EvaluationBudget $budget,
?FreeNames $names = null,
?ModifiedNames $modified = null,
)Wires the slicer to the source it walks and the budget it spends.
Parameters
$tree | SourceTree | |
$budget | EvaluationBudget | |
$names | ?FreeNames | |
$modified | ?ModifiedNames |
Calls 5
- new FreeNames line 62
- new ModifiedNames line 63
- new LoopPasses line 64
- new BranchArms line 65
- new AssignmentSteps line 66
public function sliceFrom(Node $point, array<string, true> $needs): list<Arrival>Every path from the start of the body to the point, with what each still needs.
Parameters
$point | Node | |
$needs | array<string, true> | The names the value at the point reads |
Returns
list<Arrival>Test cases 3
Called from 3
- method-call SqlCatalog\Core\Analysis\Derivation\CalleeReturns::returned() packages/sql-catalog/src/Core/Analysis/Derivation/CalleeReturns.php:142
- method-call SqlCatalog\Core\Analysis\Derivation\Deriver::solve() packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:113
- method-call SqlCatalog\Core\Analysis\Derivation\Deriver::solveAtExits() packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:140
Calls 5
- static-call Pending::needing() line 77
- method-call SourceTree::anchorOf() line 78
- method-call BackwardSlicer::leave() line 80
- new Arrival line 83
- method-call BackwardSlicer::before() line 83
public function sliceFromEnd(FunctionLike $body, array<string, true> $needs): list<Arrival>Every path from the start of a body to its end, with what each still needs.
Parameters
$body | FunctionLike | |
$needs | array<string, true> | The names read at the end of the body |
Returns
list<Arrival>Test cases 1
Called from 1
Calls 6
- function-call
array_valuesline 94 - method-call
FunctionLike::getStmts()line 94 - method-call BackwardSlicer::leave() line 96
- method-call BackwardSlicer::walkList() line 96
- function-call
countline 96 - static-call Pending::needing() line 96
The paths walked back over everything before a statement, and on out of its list.
Parameters
$statement | Stmt | |
$paths | list<Pending> |
Returns
list<Arrival>Test cases 2
Called from 5
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::sliceFrom() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:83
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leave() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:139
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leave() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:144
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leaveClosure() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:187
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses::leaveBody() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/LoopPasses.php:109
Calls 5
- method-call SourceTree::locate() line 107
- method-call BackwardSlicer::arrive() line 109
- method-call SourceTree::bodyOf() line 109
- method-call BackwardSlicer::leave() line 113
- method-call BackwardSlicer::walkList() line 113
The paths carried out of the start of a statement list, into whatever owns it.
Parameters
$owner | ?Node | |
$paths | list<Pending> |
Returns
list<Arrival>Test cases 2
Called from 4
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::sliceFrom() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:80
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::sliceFromEnd() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:96
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::before() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:113
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leaveClosure() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:184
Calls 10
- method-call BackwardSlicer::arrive() line 125
- method-call BackwardSlicer::leaveClosure() line 131
- method-call LoopPasses::isLoop() line 133
- method-call LoopPasses::leaveBody() line 134
- method-call BackwardSlicer::before() line 139
- method-call BackwardSlicer::walkList() line 139
- function-call
array_valuesline 139 - function-call
countline 139 - method-call BackwardSlicer::owningStatement() line 142
- method-call SourceTree::bodyOf() line 144
public function owningStatement(Node $owner): ?StmtThe statement an arm or a block belongs to, which is where the walk goes on from.
Parameters
$owner | Node |
Returns
?StmtTest cases 1
Called from 1
Calls 1
- method-call
Node::getAttribute()line 154
public function leaveClosure(
Closure|ArrowFunction $closure,
list<Pending> $paths,
): list<Arrival>The paths carried out of a closure into the body it is written in.
What the closure takes from outside — its use list, or for an arrow function every name that is not one of its parameters — is looked for where the closure is written. Its parameters, and any name it reads without defining, are its own: a step says so, and the walk does not look for them outside.
Parameters
$closure | Closure|ArrowFunction | |
$paths | list<Pending> |
Returns
list<Arrival>Test cases 1
Called from 1
Calls 8
- method-call BackwardSlicer::outside() line 178
- function-call
array_keysline 179 - function-call
array_diff_keyline 179 - new SliceStep line 180
- method-call SourceTree::anchorOf() line 182
- method-call BackwardSlicer::leave() line 184
- method-call BackwardSlicer::arrive() line 187
- method-call BackwardSlicer::before() line 187
public function outside(
Closure|ArrowFunction $closure,
array<string, true> $needs,
): array<string, true>The names among those needed that a closure takes from where it is written.
Parameters
$closure | Closure|ArrowFunction | |
$needs | array<string, true> |
Returns
array<string, true>Test cases 1
Called from 1
Calls 4
- function-call
is_stringline 200 - function-call
array_diff_keyline 205 - class-const FreeNames::THIS() line 207
- function-call
array_intersect_keyline 214
The paths that reached the start of a body, as arrivals there.
Parameters
$body | ?FunctionLike | |
$paths | list<Pending> |
Returns
list<Arrival>Test cases 1
Called from 5
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::before() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:109
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leave() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:125
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leave() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:128
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leave() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:144
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leaveClosure() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:187
Calls 3
- method-call SourceTree::bodyOf() line 227
- function-call
array_mapline 230 - new Arrival line 230
The paths walked back over the statements of a list, from the given position to its start.
Parameters
$list | list<Stmt> | |
$end | int | |
$paths | list<Pending> |
Returns
list<Pending>Test cases 1
Called from 7
- method-call SqlCatalog\Core\Analysis\Derivation\Objects\CallbackEffects::apply() packages/sql-catalog/src/Core/Analysis/Derivation/Objects/CallbackEffects.php:61
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::sliceFromEnd() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:96
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::before() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:113
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::leave() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:139
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::over() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:295
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::walkArms() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:323
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses::pass() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/LoopPasses.php:129
Calls 4
- method-call BackwardSlicer::allDone() line 243
- function-call
array_mergeline 248 - method-call BackwardSlicer::over() line 248
- method-call BackwardSlicer::bound() line 250
public function allDone(list<Pending> $paths): boolOne path walked back over one statement.
Parameters
$statement | Stmt | |
$path | Pending |
Returns
list<Pending>Test cases 2
Called from 1
Calls 15
- method-call EvaluationBudget::spend() line 279
- method-call Pending::exhaust() line 280
- method-call ModifiedNames::touches() line 282
- method-call AssignmentSteps::over() line 286
- method-call ModifiedNames::tracksObjects() line 288
- method-call AssignmentSteps::declaration() line 292
- method-call BackwardSlicer::walkList() line 295
- function-call
array_valuesline 295 - function-call
countline 295 - method-call LoopPasses::isLoop() line 297
- method-call BackwardSlicer::branch() line 298
- method-call LoopPasses::runs() line 298
- method-call BranchArms::of() line 300
- method-call BackwardSlicer::walkArms() line 304
- function-call
array_mapline 306
public function walkArms(list<list<Stmt>> $arms, array<string, true> $needs): list<Pending>Each arm walked back from its end, as paths that start where the branch finishes.
Parameters
$arms | list<list<Stmt>> | |
$needs | array<string, true> |
Returns
list<Pending>Test cases 1
Called from 1
Calls 4
- function-call
array_mergeline 323 - method-call BackwardSlicer::walkList() line 323
- function-call
countline 323 - static-call Pending::needing() line 323
A path taken on over the runs a branch may have taken.
The runs become one step that holds them as alternatives, rather than one path each. Running the step still runs every arm on its own, so the values an arm assigns stay together; what is saved is walking the rest of the body once per arm, which for a body of ten consecutive conditionals would be a thousand walks.
Returns
list<Pending>Test cases 1
Called from 2
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::over() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:298
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\BackwardSlicer::over() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/BackwardSlicer.php:304
Calls 3
- method-call Pending::then() line 347
- function-call
countline 347 - static-call Pending::gather() line 347
The paths with repeats merged and the rest gathered once there are too many to keep apart.
Parameters
$paths | list<Pending> |
Returns
list<Pending>Test cases 1
Called from 1
Calls 5
- function-call
array_valuesline 362 - function-call
countline 363 - class-const BackwardSlicer::MAX_PATHS() line 363
- function-call
array_sliceline 366 - static-call Pending::gather() line 369
Private surface 7§
Implementation details, listed for orientation only.
private SourceTree $treeprivate EvaluationBudget $budgetprivate FreeNames $namesprivate ModifiedNames $modifiedprivate LoopPasses $loopsprivate BranchArms $armsprivate AssignmentSteps $stepsTest cases 93§
Test cases that cover or call this symbol, from the coverage report and from the analyzed test sources.
Dedicated tests 19
BackwardSlicerTest::testAllDoneIsTrueOnlyWhenNoPathNeedsAnythingcallsBackwardSlicerTest::testArriveNamesTheNamedBodyAClosureIsWrittenIncallsBackwardSlicerTest::testBeforeAStatementNotInAnyListArrivesWhereItIscallsBackwardSlicerTest::testBeforeWalksBackOverTheStatementsAheadOfOnecallsBackwardSlicerTest::testBoundMergesRepeatsAndGathersPathsBeyondTheLimitcallsBackwardSlicerTest::testBranchHoldsSeveralRunsAsOneStepcallsBackwardSlicerTest::testLeaveCarriesAFinallyBlockOverItsTryBlockcallsBackwardSlicerTest::testLeaveCarriesPathsOutOfTheirOwnercallsBackwardSlicerTest::testLeaveClosureTakesOnlyTheUseListFromOutsidecallsBackwardSlicerTest::testOutsideIsWhatAClosureTakesFromWhereItIsWrittencallsBackwardSlicerTest::testOverStopsAPathOnceTheBudgetIsSpentcallsBackwardSlicerTest::testOverWalksDeclarationsBlocksLoopsAndConditionAssignmentscallsBackwardSlicerTest::testOwningStatementIsTheStatementAnArmBelongsTocallsBackwardSlicerTest::testSliceFromAnArrowFunctionTakesWhatItCapturesFromWhereItIsWrittencallsBackwardSlicerTest::testSliceFromANodeOutsideAnyStatementArrivesAtNothingcallsBackwardSlicerTest::testSliceFromEndWalksBackFromTheEndOfABodycallsBackwardSlicerTest::testSliceFromKeepsWhatTheCallDependsOnInTheOrderItRunscallsBackwardSlicerTest::testWalkArmsWalksEachArmFromItsEndcallsBackwardSlicerTest::testWalkListStopsOnceEveryPathIsDonecalls
Other tests reaching this symbol 74
CatalogCommandTestcallsCallEvaluatorTestcallsConstantReaderTestcallsCalleeReturnsTest::testCacheableRejectsAllocationsEvenInsideArrayscallsCalleeReturnsTest::testParametersBindsEachArgumentToThePositionItIsPassedIncallsCalleeReturnsTest::testParametersFallsBackToTheDefaultOfAParameterNotPassedcallsCalleeReturnsTest::testParametersLeavesAParameterNeitherPassedNorDefaultedOpencallsCalleeReturnsTest::testParametersLeavesAVariadicParameterOpenWhateverIsPassedcallsCalleeReturnsTest::testReadDoesNotRememberWhatAnExhaustedBudgetCutShortcallsCalleeReturnsTest::testReadEntersTheCalleeSoACallBackIntoItIsNotFollowedAgaincallsCalleeReturnsTest::testReadReturnsNullFromABodyWithoutAReturncallsCalleeReturnsTest::testReadRunsAMethodInItsOwnClassAndAFunctionInTheCallersClasscallsCalleeReturnsTest::testReadUnitesWhatEveryReturnCanReturncallsCalleeReturnsTest::testReturnedReadsNullFromABareReturncallsCalleeReturnsTest::testReturnedReadsWhatTheReturnDependsOnFromTheStartcallsCalleeReturnsTest::testReturnedUnitesEveryRunOfTheSlicecallsCalleeReturnsTest::testReturnsInFindsEveryReturnOfTheBodyInTheOrderWrittencallsCalleeReturnsTest::testReturnsInLeavesOutTheReturnsOfFunctionsAndClassesDeclaredInTheBodycallsCalleeReturnsTest::testValueOfAnswersACallWithTheSameArgumentsFromMemorycallsCalleeReturnsTest::testValueOfKeepsAbsenceDistinctFromUnresolvedReturnscallsCalleeReturnsTest::testValueOfLeavesAFunctionWithoutABodyAsACallItDidNotFollowcallsCalleeReturnsTest::testValueOfLeavesAnAbstractMethodAsACallItDidNotFollowcallsCalleeReturnsTest::testValueOfReadsWhatTheCalleeReturnscallsCalleeReturnsTest::testValueOfStopsAtACallAlreadyBeingFollowedcallsCalleeReturnsTest::testValueOfStopsAtTheDepthLimitAndFollowsJustBelowItcallsCalleeReturnsTest::testValueOfStopsOnceTheBudgetIsExhaustedcallsCallersTestcallsDeriverTest::testBinderIsTheEntryBinderTheDeriverWasWiredWithcallsDeriverTest::testEvaluatorIsTheEvaluatorTheDeriverWasWiredWithcallsDeriverTest::testSolveReadsWhatTheGoalsNeedWithTheNamesItWasGivencallsEntryBinderTestcallsCallbackEffectsTest::testApplyFollowsMutationsOfTheCallbackParametercallsCallbackEffectsTest::testApplyLeavesCallbacksWithoutAReceiverOpencallsCallbackEffectsTest::testApplyRunsClosureEffectsThroughCapturedAliasesOfItsReceivercallsCallbackEffectsTest::testBindKeepsOnlyExplicitClosureCapturesAndPassedArgumentscallsCallbackEffectsTest::testSupportedAcceptsExplicitNullAndVoidReturnscallsCallbackEffectsTest::testSupportedRejectsEarlyReturnsAndReplacementQueriescallsPropertyWritesTest::testValuesOfCollectsWhatEveryWriterLeavescallsPropertyWritesTest::testValuesOfSkipsTheWritersOnceTheBudgetIsSpentcallsLoopPassesTest::testBindingIsAStepOnlyForAPathThatNeedsTheLoopsVariablescallsLoopPassesTest::testBodyOfIsWhatALoopRepeatscallsLoopPassesTest::testBoundSaysWhetherAPathTookOneOfTheLoopsPassescallsLoopPassesTest::testContinuesSaysWhetherAnotherPassCouldChangeWhatIsNeededcallsLoopPassesTest::testEnteringReadsWhatALoopGoesOverBeforeItsFirstPasscallsLoopPassesTest::testExpressionsWalkBackOverAListLastFirstcallsLoopPassesTest::testIsLoopRecognisesEveryKindOfLoopcallsLoopPassesTest::testLeaveBodyFollowsAPointInsideALoopBackThroughEarlierPassescallsLoopPassesTest::testPassWalksBackOverOneWholePasscallsLoopPassesTest::testRunsListTheStatementAfterEachNumberOfPassesUpToTheLimitcallsLoopPassesTest::testRunsOfADoWhileAlwaysIncludeAPasscallsLoopPassesTest::testRunsStopOnceAPassCannotChangeWhatIsNeededcallsLoopPassesTest::testRunsTakeExactlyAsManyPassesAsAWrittenOutArrayHasElementscallsLoopPassesTest::testWrittenPassesCountsOnlyAnArrayWrittenOutInFullcallsSliceExecutorTestcallsExpressionEvaluatorTestcallsRegistryTestcallsInterpreterTestcallsModelQueriesTestcallsReferenceEvaluatorTestcallsCallContextTestcallsModelContextTest::testKeepsTheModelContractInputscallsQueryModelInterfaceTestcallsBuilderCallsTestcallsBuilderQueriesTestcallsCallbackModelTest::testApplyRunsSourceDeclaredLocalScopescallsCallbackModelTest::testCheckedPreservesAVisibleGapWhenTheCallbackExceedsItsBudgetcallsCallbackModelTest::testClosedRejectsWidenedResultsAndForeignIdentitiescallsCallbackModelTest::testConditionalKeepsBothOutcomesOfWhenAndUnlesscallsCallbackModelTest::testNestedRestoresOuterClausesAndGroupsOnlyNewPredicatescallsCallModelTestcallsLaravelExtensionTest::testModelsRegistersLaravelSemanticsThroughTheOptionalContractcallsAnalyzerTestcallsJsonReporterTestcallsTextReporterTestcalls
Relations§
Instantiated in 1
Method calls 7
- method-call SqlCatalog\Core\Analysis\Derivation\CalleeReturns::returned() packages/sql-catalog/src/Core/Analysis/Derivation/CalleeReturns.php:142
- method-call SqlCatalog\Core\Analysis\Derivation\Deriver::solve() packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:113
- method-call SqlCatalog\Core\Analysis\Derivation\Deriver::solveAtExits() packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:137
- method-call SqlCatalog\Core\Analysis\Derivation\Deriver::solveAtExits() packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:140
- method-call SqlCatalog\Core\Analysis\Derivation\Objects\CallbackEffects::apply() packages/sql-catalog/src/Core/Analysis/Derivation/Objects/CallbackEffects.php:61
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses::leaveBody() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/LoopPasses.php:109
- method-call SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses::pass() packages/sql-catalog/src/Core/Analysis/Derivation/Slice/LoopPasses.php:129
Type declarations 7
- type SqlCatalog\Core\Analysis\Derivation\CalleeReturns packages/sql-catalog/src/Core/Analysis/Derivation/CalleeReturns.php:33
- type SqlCatalog\Core\Analysis\Derivation\CalleeReturns packages/sql-catalog/src/Core/Analysis/Derivation/CalleeReturns.php:47
- type SqlCatalog\Core\Analysis\Derivation\Deriver packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:46
- type SqlCatalog\Core\Analysis\Derivation\Deriver packages/sql-catalog/src/Core/Analysis/Derivation/Deriver.php:68
- type SqlCatalog\Core\Analysis\Derivation\Objects\CallbackEffects packages/sql-catalog/src/Core/Analysis/Derivation/Objects/CallbackEffects.php:27
- type SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses packages/sql-catalog/src/Core/Analysis/Derivation/Slice/LoopPasses.php:30
- type SqlCatalog\Core\Analysis\Derivation\Slice\LoopPasses packages/sql-catalog/src/Core/Analysis/Derivation/Slice/LoopPasses.php:44