Skip to content

Commit 4588e73

Browse files
committed
Precise exception tracking for everyone
1 parent 8933c7e commit 4588e73

File tree

7 files changed

+57
-114
lines changed

7 files changed

+57
-114
lines changed

conf/bleedingEdge.neon

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ parameters:
1717
objectFromNewClass: true
1818
skipCheckGenericClasses: []
1919
rememberFunctionValues: true
20-
preciseExceptionTracking: true
2120
apiRules: true
2221
deepInspectTypes: true
2322
neverInGenericReturnType: true

conf/config.level4.neon

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ rules:
66
- PHPStan\Rules\Comparison\NumberComparisonOperatorsConstantConditionRule
77
- PHPStan\Rules\DeadCode\NoopRule
88
- PHPStan\Rules\DeadCode\UnreachableStatementRule
9+
- PHPStan\Rules\Exceptions\CatchWithUnthrownExceptionRule
10+
- PHPStan\Rules\Exceptions\OverwrittenExitPointByFinallyRule
911
- PHPStan\Rules\Functions\CallToFunctionStamentWithoutSideEffectsRule
1012
- PHPStan\Rules\Methods\CallToConstructorStatementWithoutSideEffectsRule
1113
- PHPStan\Rules\Methods\CallToMethodStamentWithoutSideEffectsRule
@@ -17,10 +19,6 @@ rules:
1719
- PHPStan\Rules\TooWideTypehints\TooWideFunctionReturnTypehintRule
1820

1921
conditionalTags:
20-
PHPStan\Rules\Exceptions\CatchWithUnthrownExceptionRule:
21-
phpstan.rules.rule: %featureToggles.preciseExceptionTracking%
22-
PHPStan\Rules\Exceptions\OverwrittenExitPointByFinallyRule:
23-
phpstan.rules.rule: %featureToggles.preciseExceptionTracking%
2422
PHPStan\Rules\DeadCode\UnusedPrivateConstantRule:
2523
phpstan.rules.rule: %featureToggles.unusedClassElements%
2624
PHPStan\Rules\DeadCode\UnusedPrivateMethodRule:
@@ -149,12 +147,6 @@ services:
149147
tags:
150148
- phpstan.rules.rule
151149

152-
-
153-
class: PHPStan\Rules\Exceptions\CatchWithUnthrownExceptionRule
154-
155-
-
156-
class: PHPStan\Rules\Exceptions\OverwrittenExitPointByFinallyRule
157-
158150
-
159151
class: PHPStan\Rules\TooWideTypehints\TooWideMethodReturnTypehintRule
160152
arguments:

conf/config.neon

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ parameters:
4242
- RecursiveArrayIterator
4343
- WeakMap
4444
rememberFunctionValues: false
45-
preciseExceptionTracking: false
4645
apiRules: false
4746
deepInspectTypes: false
4847
neverInGenericReturnType: false
@@ -228,7 +227,6 @@ parametersSchema:
228227
objectFromNewClass: bool(),
229228
skipCheckGenericClasses: listOf(string()),
230229
rememberFunctionValues: bool(),
231-
preciseExceptionTracking: bool(),
232230
apiRules: bool(),
233231
deepInspectTypes: bool(),
234232
neverInGenericReturnType: bool(),
@@ -479,7 +477,6 @@ services:
479477
earlyTerminatingMethodCalls: %earlyTerminatingMethodCalls%
480478
earlyTerminatingFunctionCalls: %earlyTerminatingFunctionCalls%
481479
implicitThrows: %implicitThrows%
482-
preciseExceptionTracking: %featureToggles.preciseExceptionTracking%
483480

484481
-
485482
implement: PHPStan\Analyser\ResultCache\ResultCacheManagerFactory

src/Analyser/NodeScopeResolver.php

Lines changed: 55 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,6 @@ class NodeScopeResolver
160160

161161
private bool $implicitThrows;
162162

163-
private bool $preciseExceptionTracking;
164-
165163
/** @var bool[] filePath(string) => bool(true) */
166164
private array $analysedFiles = [];
167165

@@ -178,7 +176,6 @@ class NodeScopeResolver
178176
* @param string[][] $earlyTerminatingMethodCalls className(string) => methods(string[])
179177
* @param array<int, string> $earlyTerminatingFunctionCalls
180178
* @param bool $implicitThrows
181-
* @param bool $preciseExceptionTracking
182179
*/
183180
public function __construct(
184181
ReflectionProvider $reflectionProvider,
@@ -196,8 +193,7 @@ public function __construct(
196193
bool $polluteScopeWithAlwaysIterableForeach,
197194
array $earlyTerminatingMethodCalls,
198195
array $earlyTerminatingFunctionCalls,
199-
bool $implicitThrows,
200-
bool $preciseExceptionTracking
196+
bool $implicitThrows
201197
)
202198
{
203199
$this->reflectionProvider = $reflectionProvider;
@@ -216,7 +212,6 @@ public function __construct(
216212
$this->earlyTerminatingMethodCalls = $earlyTerminatingMethodCalls;
217213
$this->earlyTerminatingFunctionCalls = $earlyTerminatingFunctionCalls;
218214
$this->implicitThrows = $implicitThrows;
219-
$this->preciseExceptionTracking = $preciseExceptionTracking;
220215
}
221216

222217
/**
@@ -1180,89 +1175,78 @@ private function processStmtNode(
11801175
foreach ($stmt->catches as $catchNode) {
11811176
$nodeCallback($catchNode, $scope);
11821177

1183-
if ($this->preciseExceptionTracking) {
1184-
$catchType = TypeCombinator::union(...array_map(static function (Name $name): Type {
1185-
return new ObjectType($name->toString());
1186-
}, $catchNode->types));
1187-
$originalCatchType = $catchType;
1188-
$catchType = TypeCombinator::remove($catchType, $pastCatchTypes);
1189-
$pastCatchTypes = TypeCombinator::union($pastCatchTypes, $originalCatchType);
1190-
$matchingThrowPoints = [];
1191-
$newThrowPoints = [];
1192-
foreach ($throwPoints as $throwPoint) {
1193-
if (!$throwPoint->isExplicit() && !$catchType->isSuperTypeOf(new ObjectType(\Throwable::class))->yes()) {
1194-
continue;
1195-
}
1196-
$isSuperType = $catchType->isSuperTypeOf($throwPoint->getType());
1197-
if ($isSuperType->no()) {
1198-
continue;
1199-
}
1178+
$catchType = TypeCombinator::union(...array_map(static function (Name $name): Type {
1179+
return new ObjectType($name->toString());
1180+
}, $catchNode->types));
1181+
$originalCatchType = $catchType;
1182+
$catchType = TypeCombinator::remove($catchType, $pastCatchTypes);
1183+
$pastCatchTypes = TypeCombinator::union($pastCatchTypes, $originalCatchType);
1184+
$matchingThrowPoints = [];
1185+
$newThrowPoints = [];
1186+
foreach ($throwPoints as $throwPoint) {
1187+
if (!$throwPoint->isExplicit() && !$catchType->isSuperTypeOf(new ObjectType(\Throwable::class))->yes()) {
1188+
continue;
1189+
}
1190+
$isSuperType = $catchType->isSuperTypeOf($throwPoint->getType());
1191+
if ($isSuperType->no()) {
1192+
continue;
1193+
}
1194+
$matchingThrowPoints[] = $throwPoint;
1195+
}
1196+
$hasExplicit = count($matchingThrowPoints) > 0;
1197+
foreach ($throwPoints as $throwPoint) {
1198+
$isSuperType = $catchType->isSuperTypeOf($throwPoint->getType());
1199+
if (!$hasExplicit && !$isSuperType->no()) {
12001200
$matchingThrowPoints[] = $throwPoint;
12011201
}
1202-
$hasExplicit = count($matchingThrowPoints) > 0;
1203-
foreach ($throwPoints as $throwPoint) {
1204-
$isSuperType = $catchType->isSuperTypeOf($throwPoint->getType());
1205-
if (!$hasExplicit && !$isSuperType->no()) {
1206-
$matchingThrowPoints[] = $throwPoint;
1207-
}
1208-
if ($isSuperType->yes()) {
1209-
continue;
1210-
}
1211-
$newThrowPoints[] = $throwPoint->subtractCatchType($catchType);
1202+
if ($isSuperType->yes()) {
1203+
continue;
12121204
}
1213-
$throwPoints = $newThrowPoints;
1214-
1215-
if (count($matchingThrowPoints) === 0) {
1216-
$throwableThrowPoints = [];
1217-
if ($originalCatchType->isSuperTypeOf(new ObjectType(\Throwable::class))->yes()) {
1218-
foreach ($branchScopeResult->getThrowPoints() as $originalThrowPoint) {
1219-
if (!$originalThrowPoint->canContainAnyThrowable()) {
1220-
continue;
1221-
}
1205+
$newThrowPoints[] = $throwPoint->subtractCatchType($catchType);
1206+
}
1207+
$throwPoints = $newThrowPoints;
12221208

1223-
$throwableThrowPoints[] = $originalThrowPoint;
1209+
if (count($matchingThrowPoints) === 0) {
1210+
$throwableThrowPoints = [];
1211+
if ($originalCatchType->isSuperTypeOf(new ObjectType(\Throwable::class))->yes()) {
1212+
foreach ($branchScopeResult->getThrowPoints() as $originalThrowPoint) {
1213+
if (!$originalThrowPoint->canContainAnyThrowable()) {
1214+
continue;
12241215
}
1225-
}
12261216

1227-
if (count($throwableThrowPoints) === 0) {
1228-
$nodeCallback(new CatchWithUnthrownExceptionNode($catchNode, $catchType, $originalCatchType), $scope);
1229-
continue;
1217+
$throwableThrowPoints[] = $originalThrowPoint;
12301218
}
1231-
1232-
$matchingThrowPoints = $throwableThrowPoints;
12331219
}
12341220

1235-
$catchScope = null;
1236-
foreach ($matchingThrowPoints as $matchingThrowPoint) {
1237-
if ($catchScope === null) {
1238-
$catchScope = $matchingThrowPoint->getScope();
1239-
} else {
1240-
$catchScope = $catchScope->mergeWith($matchingThrowPoint->getScope());
1241-
}
1221+
if (count($throwableThrowPoints) === 0) {
1222+
$nodeCallback(new CatchWithUnthrownExceptionNode($catchNode, $catchType, $originalCatchType), $scope);
1223+
continue;
12421224
}
12431225

1244-
$variableName = null;
1245-
if ($catchNode->var !== null) {
1246-
if (!is_string($catchNode->var->name)) {
1247-
throw new \PHPStan\ShouldNotHappenException();
1248-
}
1226+
$matchingThrowPoints = $throwableThrowPoints;
1227+
}
12491228

1250-
$variableName = $catchNode->var->name;
1229+
$catchScope = null;
1230+
foreach ($matchingThrowPoints as $matchingThrowPoint) {
1231+
if ($catchScope === null) {
1232+
$catchScope = $matchingThrowPoint->getScope();
1233+
} else {
1234+
$catchScope = $catchScope->mergeWith($matchingThrowPoint->getScope());
12511235
}
1236+
}
12521237

1253-
$catchScopeResult = $this->processStmtNodes($catchNode, $catchNode->stmts, $catchScope->enterCatchType($catchType, $variableName), $nodeCallback);
1254-
$catchScopeForFinally = $catchScopeResult->getScope();
1255-
} else {
1256-
$initialScope = $scope;
1257-
if (count($throwPoints) > 0) {
1258-
$initialScope = $throwPoints[0]->getScope();
1238+
$variableName = null;
1239+
if ($catchNode->var !== null) {
1240+
if (!is_string($catchNode->var->name)) {
1241+
throw new \PHPStan\ShouldNotHappenException();
12591242
}
12601243

1261-
$catchScopeForFinally = $this->processCatchNode($catchNode, $branchScope, $nodeCallback)->getScope();
1262-
$catchScopeResult = $this->processCatchNode($catchNode, $initialScope->mergeWith($branchScope), static function (): void {
1263-
});
1244+
$variableName = $catchNode->var->name;
12641245
}
12651246

1247+
$catchScopeResult = $this->processStmtNodes($catchNode, $catchNode->stmts, $catchScope->enterCatchType($catchType, $variableName), $nodeCallback);
1248+
$catchScopeForFinally = $catchScopeResult->getScope();
1249+
12661250
$finalScope = $catchScopeResult->isAlwaysTerminating() ? $finalScope : $catchScopeResult->getScope()->mergeWith($finalScope);
12671251
$alwaysTerminating = $alwaysTerminating && $catchScopeResult->isAlwaysTerminating();
12681252
$hasYield = $hasYield || $catchScopeResult->hasYield();
@@ -1501,31 +1485,6 @@ private function createAstClassReflection(Node\Stmt\ClassLike $stmt, Scope $scop
15011485
);
15021486
}
15031487

1504-
/**
1505-
* @param Node\Stmt\Catch_ $catchNode
1506-
* @param MutatingScope $catchScope
1507-
* @param callable(\PhpParser\Node $node, Scope $scope): void $nodeCallback
1508-
* @return StatementResult
1509-
*/
1510-
private function processCatchNode(
1511-
Node\Stmt\Catch_ $catchNode,
1512-
MutatingScope $catchScope,
1513-
callable $nodeCallback
1514-
): StatementResult
1515-
{
1516-
$variableName = null;
1517-
if ($catchNode->var !== null) {
1518-
if (!is_string($catchNode->var->name)) {
1519-
throw new \PHPStan\ShouldNotHappenException();
1520-
}
1521-
1522-
$variableName = $catchNode->var->name;
1523-
}
1524-
1525-
$catchScope = $catchScope->enterCatch($catchNode->types, $variableName);
1526-
return $this->processStmtNodes($catchNode, $catchNode->stmts, $catchScope, $nodeCallback);
1527-
}
1528-
15291488
private function lookForEnterVariableAssign(MutatingScope $scope, Expr $expr): MutatingScope
15301489
{
15311490
if (!$expr instanceof ArrayDimFetch || $expr->dim !== null) {

src/Testing/RuleTestCase.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ private function getAnalyser(): Analyser
8888
$this->shouldPolluteScopeWithAlwaysIterableForeach(),
8989
[],
9090
[],
91-
true,
9291
true
9392
);
9493
$fileAnalyser = new FileAnalyser(

src/Testing/TypeInferenceTestCase.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ public function processFile(
7777
true,
7878
$this->getEarlyTerminatingMethodCalls(),
7979
$this->getEarlyTerminatingFunctionCalls(),
80-
true,
8180
true
8281
);
8382
$resolver->setAnalysedFiles(array_map(static function (string $file) use ($fileHelper): string {

tests/PHPStan/Analyser/AnalyserTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,9 @@ private function createAnalyser(bool $reportUnmatchedIgnoredErrors): \PHPStan\An
515515
$typeSpecifier,
516516
self::getContainer()->getByType(DynamicThrowTypeExtensionProvider::class),
517517
false,
518-
false,
519518
true,
520519
[],
521520
[],
522-
true,
523521
true
524522
);
525523
$lexer = new \PhpParser\Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos']]);

0 commit comments

Comments
 (0)