@@ -246,7 +246,7 @@ public function processNodes(
246
246
continue ;
247
247
}
248
248
249
- $ statementResult = $ this ->processStmtNode ($ node , $ scope , $ nodeCallback );
249
+ $ statementResult = $ this ->processStmtNode ($ node , $ scope , $ nodeCallback, StatementContext:: createTopLevel () );
250
250
$ scope = $ statementResult ->getScope ();
251
251
if (!$ statementResult ->isAlwaysTerminating ()) {
252
252
continue ;
@@ -274,8 +274,12 @@ public function processStmtNodes(
274
274
array $ stmts ,
275
275
MutatingScope $ scope ,
276
276
callable $ nodeCallback ,
277
+ ?StatementContext $ context = null ,
277
278
): StatementResult
278
279
{
280
+ if ($ context === null ) {
281
+ $ context = StatementContext::createTopLevel ();
282
+ }
279
283
$ exitPoints = [];
280
284
$ throwPoints = [];
281
285
$ alreadyTerminated = false ;
@@ -290,6 +294,7 @@ public function processStmtNodes(
290
294
$ stmt ,
291
295
$ scope ,
292
296
$ nodeCallback ,
297
+ $ context ,
293
298
);
294
299
$ scope = $ statementResult ->getScope ();
295
300
$ hasYield = $ hasYield || $ statementResult ->hasYield ();
@@ -346,6 +351,7 @@ private function processStmtNode(
346
351
Node \Stmt $ stmt ,
347
352
MutatingScope $ scope ,
348
353
callable $ nodeCallback ,
354
+ StatementContext $ context ,
349
355
): StatementResult
350
356
{
351
357
if (
@@ -460,7 +466,7 @@ private function processStmtNode(
460
466
}
461
467
462
468
$ gatheredReturnStatements [] = new ReturnStatement ($ scope , $ node );
463
- });
469
+ }, StatementContext:: createTopLevel () );
464
470
465
471
$ nodeCallback (new FunctionReturnStatementsNode (
466
472
$ stmt ,
@@ -560,7 +566,7 @@ private function processStmtNode(
560
566
}
561
567
562
568
$ gatheredReturnStatements [] = new ReturnStatement ($ scope , $ node );
563
- });
569
+ }, StatementContext:: createTopLevel () );
564
570
$ nodeCallback (new MethodReturnStatementsNode (
565
571
$ stmt ,
566
572
$ gatheredReturnStatements ,
@@ -629,7 +635,7 @@ private function processStmtNode(
629
635
$ scope = $ scope ->enterNamespace ($ stmt ->name ->toString ());
630
636
}
631
637
632
- $ scope = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ scope , $ nodeCallback )->getScope ();
638
+ $ scope = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ scope , $ nodeCallback, $ context )->getScope ();
633
639
$ hasYield = false ;
634
640
$ throwPoints = [];
635
641
} elseif ($ stmt instanceof Node \Stmt \Trait_) {
@@ -659,7 +665,7 @@ private function processStmtNode(
659
665
$ classStatementsGatherer = new ClassStatementsGatherer ($ classReflection , $ nodeCallback );
660
666
$ this ->processAttributeGroups ($ stmt ->attrGroups , $ classScope , $ classStatementsGatherer );
661
667
662
- $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ classScope , $ classStatementsGatherer );
668
+ $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ classScope , $ classStatementsGatherer, $ context );
663
669
$ nodeCallback (new ClassPropertiesNode ($ stmt , $ this ->readWritePropertiesExtensionProvider , $ classStatementsGatherer ->getProperties (), $ classStatementsGatherer ->getPropertyUsages (), $ classStatementsGatherer ->getMethodCalls ()), $ classScope );
664
670
$ nodeCallback (new ClassMethodsNode ($ stmt , $ classStatementsGatherer ->getMethods (), $ classStatementsGatherer ->getMethodCalls ()), $ classScope );
665
671
$ nodeCallback (new ClassConstantsNode ($ stmt , $ classStatementsGatherer ->getConstants (), $ classStatementsGatherer ->getConstantFetches ()), $ classScope );
@@ -670,7 +676,7 @@ private function processStmtNode(
670
676
$ this ->processAttributeGroups ($ stmt ->attrGroups , $ scope , $ nodeCallback );
671
677
672
678
foreach ($ stmt ->props as $ prop ) {
673
- $ this ->processStmtNode ($ prop , $ scope , $ nodeCallback );
679
+ $ this ->processStmtNode ($ prop , $ scope , $ nodeCallback, $ context );
674
680
[,,,,,,,,,,$ isReadOnly , $ docComment , ,,,$ varTags ] = $ this ->getPhpDocs ($ scope , $ stmt );
675
681
if (!$ scope ->isInClass ()) {
676
682
throw new ShouldNotHappenException ();
@@ -726,7 +732,7 @@ private function processStmtNode(
726
732
$ alwaysTerminating = true ;
727
733
$ hasYield = $ condResult ->hasYield ();
728
734
729
- $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback );
735
+ $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback, $ context );
730
736
731
737
if (!$ conditionType instanceof ConstantBooleanType || $ conditionType ->getValue ()) {
732
738
$ exitPoints = $ branchScopeStatementResult ->getExitPoints ();
@@ -747,7 +753,7 @@ private function processStmtNode(
747
753
$ condResult = $ this ->processExprNode ($ elseif ->cond , $ condScope , $ nodeCallback , ExpressionContext::createDeep ());
748
754
$ throwPoints = array_merge ($ throwPoints , $ condResult ->getThrowPoints ());
749
755
$ condScope = $ condResult ->getScope ();
750
- $ branchScopeStatementResult = $ this ->processStmtNodes ($ elseif , $ elseif ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback );
756
+ $ branchScopeStatementResult = $ this ->processStmtNodes ($ elseif , $ elseif ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback, $ context );
751
757
752
758
if (
753
759
!$ ifAlwaysTrue
@@ -784,7 +790,7 @@ private function processStmtNode(
784
790
}
785
791
} else {
786
792
$ nodeCallback ($ stmt ->else , $ scope );
787
- $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt ->else , $ stmt ->else ->stmts , $ scope , $ nodeCallback );
793
+ $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt ->else , $ stmt ->else ->stmts , $ scope , $ nodeCallback, $ context );
788
794
789
795
if (!$ ifAlwaysTrue && !$ lastElseIfConditionIsTrue ) {
790
796
$ exitPoints = array_merge ($ exitPoints , $ branchScopeStatementResult ->getExitPoints ());
@@ -825,12 +831,15 @@ private function processStmtNode(
825
831
$ bodyScope = $ bodyScope ->mergeWith ($ this ->polluteScopeWithAlwaysIterableForeach ? $ scope ->filterByTruthyValue ($ arrayComparisonExpr ) : $ scope );
826
832
$ bodyScope = $ this ->enterForeach ($ bodyScope , $ stmt );
827
833
$ bodyScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , static function (): void {
828
- })->filterOutLoopExitPoints ();
834
+ }, $ context -> enterDeep () )->filterOutLoopExitPoints ();
829
835
$ alwaysTerminating = $ bodyScopeResult ->isAlwaysTerminating ();
830
836
$ bodyScope = $ bodyScopeResult ->getScope ();
831
837
foreach ($ bodyScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
832
838
$ bodyScope = $ bodyScope ->mergeWith ($ continueExitPoint ->getScope ());
833
839
}
840
+ if (!$ context ->isTopLevel ()) {
841
+ break ;
842
+ }
834
843
if ($ bodyScope ->equals ($ prevScope )) {
835
844
break ;
836
845
}
@@ -843,7 +852,7 @@ private function processStmtNode(
843
852
844
853
$ bodyScope = $ bodyScope ->mergeWith ($ this ->polluteScopeWithAlwaysIterableForeach ? $ scope ->filterByTruthyValue ($ arrayComparisonExpr ) : $ scope );
845
854
$ bodyScope = $ this ->enterForeach ($ bodyScope , $ stmt );
846
- $ finalScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback )->filterOutLoopExitPoints ();
855
+ $ finalScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback, $ context )->filterOutLoopExitPoints ();
847
856
$ finalScope = $ finalScopeResult ->getScope ();
848
857
foreach ($ finalScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
849
858
$ finalScope = $ continueExitPoint ->getScope ()->mergeWith ($ finalScope );
@@ -891,12 +900,15 @@ private function processStmtNode(
891
900
$ bodyScope = $ this ->processExprNode ($ stmt ->cond , $ bodyScope , static function (): void {
892
901
}, ExpressionContext::createDeep ())->getTruthyScope ();
893
902
$ bodyScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , static function (): void {
894
- })->filterOutLoopExitPoints ();
903
+ }, $ context -> enterDeep () )->filterOutLoopExitPoints ();
895
904
$ alwaysTerminating = $ bodyScopeResult ->isAlwaysTerminating ();
896
905
$ bodyScope = $ bodyScopeResult ->getScope ();
897
906
foreach ($ bodyScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
898
907
$ bodyScope = $ bodyScope ->mergeWith ($ continueExitPoint ->getScope ());
899
908
}
909
+ if (!$ context ->isTopLevel ()) {
910
+ break ;
911
+ }
900
912
if ($ bodyScope ->equals ($ prevScope )) {
901
913
break ;
902
914
}
@@ -910,7 +922,7 @@ private function processStmtNode(
910
922
$ bodyScope = $ bodyScope ->mergeWith ($ scope );
911
923
$ bodyScopeMaybeRan = $ bodyScope ;
912
924
$ bodyScope = $ this ->processExprNode ($ stmt ->cond , $ bodyScope , $ nodeCallback , ExpressionContext::createDeep ())->getTruthyScope ();
913
- $ finalScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback )->filterOutLoopExitPoints ();
925
+ $ finalScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback, $ context )->filterOutLoopExitPoints ();
914
926
$ finalScope = $ finalScopeResult ->getScope ()->filterByFalseyValue ($ stmt ->cond );
915
927
foreach ($ finalScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
916
928
$ finalScope = $ finalScope ->mergeWith ($ continueExitPoint ->getScope ());
@@ -965,7 +977,7 @@ private function processStmtNode(
965
977
$ prevScope = $ bodyScope ;
966
978
$ bodyScope = $ bodyScope ->mergeWith ($ scope );
967
979
$ bodyScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , static function (): void {
968
- })->filterOutLoopExitPoints ();
980
+ }, $ context -> enterDeep () )->filterOutLoopExitPoints ();
969
981
$ alwaysTerminating = $ bodyScopeResult ->isAlwaysTerminating ();
970
982
$ bodyScope = $ bodyScopeResult ->getScope ();
971
983
foreach ($ bodyScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
@@ -977,6 +989,9 @@ private function processStmtNode(
977
989
}
978
990
$ bodyScope = $ this ->processExprNode ($ stmt ->cond , $ bodyScope , static function (): void {
979
991
}, ExpressionContext::createDeep ())->getTruthyScope ();
992
+ if (!$ context ->isTopLevel ()) {
993
+ break ;
994
+ }
980
995
if ($ bodyScope ->equals ($ prevScope )) {
981
996
break ;
982
997
}
@@ -989,7 +1004,7 @@ private function processStmtNode(
989
1004
990
1005
$ bodyScope = $ bodyScope ->mergeWith ($ scope );
991
1006
992
- $ bodyScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback )->filterOutLoopExitPoints ();
1007
+ $ bodyScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback, $ context )->filterOutLoopExitPoints ();
993
1008
$ bodyScope = $ bodyScopeResult ->getScope ();
994
1009
foreach ($ bodyScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
995
1010
$ bodyScope = $ bodyScope ->mergeWith ($ continueExitPoint ->getScope ());
@@ -1065,7 +1080,7 @@ private function processStmtNode(
1065
1080
}, ExpressionContext::createDeep ())->getTruthyScope ();
1066
1081
}
1067
1082
$ bodyScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , static function (): void {
1068
- })->filterOutLoopExitPoints ();
1083
+ }, $ context -> enterDeep () )->filterOutLoopExitPoints ();
1069
1084
$ alwaysTerminating = $ bodyScopeResult ->isAlwaysTerminating ();
1070
1085
$ bodyScope = $ bodyScopeResult ->getScope ();
1071
1086
foreach ($ bodyScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
@@ -1079,6 +1094,10 @@ private function processStmtNode(
1079
1094
$ throwPoints = array_merge ($ throwPoints , $ exprResult ->getThrowPoints ());
1080
1095
}
1081
1096
1097
+ if (!$ context ->isTopLevel ()) {
1098
+ break ;
1099
+ }
1100
+
1082
1101
if ($ bodyScope ->equals ($ prevScope )) {
1083
1102
break ;
1084
1103
}
@@ -1094,7 +1113,7 @@ private function processStmtNode(
1094
1113
$ bodyScope = $ this ->processExprNode ($ condExpr , $ bodyScope , $ nodeCallback , ExpressionContext::createDeep ())->getTruthyScope ();
1095
1114
}
1096
1115
1097
- $ finalScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback )->filterOutLoopExitPoints ();
1116
+ $ finalScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ bodyScope , $ nodeCallback, $ context )->filterOutLoopExitPoints ();
1098
1117
$ finalScope = $ finalScopeResult ->getScope ();
1099
1118
foreach ($ finalScopeResult ->getExitPointsByType (Continue_::class) as $ continueExitPoint ) {
1100
1119
$ finalScope = $ continueExitPoint ->getScope ()->mergeWith ($ finalScope );
@@ -1164,7 +1183,7 @@ private function processStmtNode(
1164
1183
}
1165
1184
1166
1185
$ branchScope = $ branchScope ->mergeWith ($ prevScope );
1167
- $ branchScopeResult = $ this ->processStmtNodes ($ caseNode , $ caseNode ->stmts , $ branchScope , $ nodeCallback );
1186
+ $ branchScopeResult = $ this ->processStmtNodes ($ caseNode , $ caseNode ->stmts , $ branchScope , $ nodeCallback, $ context );
1168
1187
$ branchScope = $ branchScopeResult ->getScope ();
1169
1188
$ branchFinalScopeResult = $ branchScopeResult ->filterOutLoopExitPoints ();
1170
1189
$ hasYield = $ hasYield || $ branchFinalScopeResult ->hasYield ();
@@ -1208,7 +1227,7 @@ private function processStmtNode(
1208
1227
1209
1228
return new StatementResult ($ finalScope , $ hasYield , $ alwaysTerminating , $ exitPointsForOuterLoop , $ throwPoints );
1210
1229
} elseif ($ stmt instanceof TryCatch) {
1211
- $ branchScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ scope , $ nodeCallback );
1230
+ $ branchScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ scope , $ nodeCallback, $ context );
1212
1231
$ branchScope = $ branchScopeResult ->getScope ();
1213
1232
$ finalScope = $ branchScopeResult ->isAlwaysTerminating () ? null : $ branchScope ;
1214
1233
@@ -1311,7 +1330,7 @@ private function processStmtNode(
1311
1330
$ variableName = $ catchNode ->var ->name ;
1312
1331
}
1313
1332
1314
- $ catchScopeResult = $ this ->processStmtNodes ($ catchNode , $ catchNode ->stmts , $ catchScope ->enterCatchType ($ catchType , $ variableName ), $ nodeCallback );
1333
+ $ catchScopeResult = $ this ->processStmtNodes ($ catchNode , $ catchNode ->stmts , $ catchScope ->enterCatchType ($ catchType , $ variableName ), $ nodeCallback, $ context );
1315
1334
$ catchScopeForFinally = $ catchScopeResult ->getScope ();
1316
1335
1317
1336
$ finalScope = $ catchScopeResult ->isAlwaysTerminating () ? $ finalScope : $ catchScopeResult ->getScope ()->mergeWith ($ finalScope );
@@ -1355,7 +1374,7 @@ private function processStmtNode(
1355
1374
1356
1375
if ($ finallyScope !== null && $ stmt ->finally !== null ) {
1357
1376
$ originalFinallyScope = $ finallyScope ;
1358
- $ finallyResult = $ this ->processStmtNodes ($ stmt ->finally , $ stmt ->finally ->stmts , $ finallyScope , $ nodeCallback );
1377
+ $ finallyResult = $ this ->processStmtNodes ($ stmt ->finally , $ stmt ->finally ->stmts , $ finallyScope , $ nodeCallback, $ context );
1359
1378
$ alwaysTerminating = $ alwaysTerminating || $ finallyResult ->isAlwaysTerminating ();
1360
1379
$ hasYield = $ hasYield || $ finallyResult ->hasYield ();
1361
1380
$ throwPointsForLater = array_merge ($ throwPointsForLater , $ finallyResult ->getThrowPoints ());
@@ -1384,7 +1403,7 @@ private function processStmtNode(
1384
1403
$ hasYield = false ;
1385
1404
$ throwPoints = [];
1386
1405
foreach ($ stmt ->uses as $ use ) {
1387
- $ this ->processStmtNode ($ use , $ scope , $ nodeCallback );
1406
+ $ this ->processStmtNode ($ use , $ scope , $ nodeCallback, $ context );
1388
1407
}
1389
1408
} elseif ($ stmt instanceof Node \Stmt \Global_) {
1390
1409
$ hasYield = false ;
@@ -1412,7 +1431,7 @@ private function processStmtNode(
1412
1431
1413
1432
$ vars = [];
1414
1433
foreach ($ stmt ->vars as $ var ) {
1415
- $ scope = $ this ->processStmtNode ($ var , $ scope , $ nodeCallback )->getScope ();
1434
+ $ scope = $ this ->processStmtNode ($ var , $ scope , $ nodeCallback, $ context )->getScope ();
1416
1435
if (!is_string ($ var ->var ->name )) {
1417
1436
continue ;
1418
1437
}
@@ -2542,7 +2561,7 @@ static function (?Type $offsetType, Type $valueType, bool $optional) use (&$arra
2542
2561
}
2543
2562
} elseif ($ expr ->class instanceof Class_) {
2544
2563
$ this ->reflectionProvider ->getAnonymousClassReflection ($ expr ->class , $ scope ); // populates $expr->class->name
2545
- $ this ->processStmtNode ($ expr ->class , $ scope , $ nodeCallback );
2564
+ $ this ->processStmtNode ($ expr ->class , $ scope , $ nodeCallback, StatementContext:: createTopLevel () );
2546
2565
} else {
2547
2566
$ className = $ scope ->resolveName ($ expr ->class );
2548
2567
if ($ this ->reflectionProvider ->hasClass ($ className )) {
@@ -3149,7 +3168,7 @@ private function processClosureNode(
3149
3168
$ gatheredReturnStatements [] = new ReturnStatement ($ scope , $ node );
3150
3169
};
3151
3170
if (count ($ byRefUses ) === 0 ) {
3152
- $ statementResult = $ this ->processStmtNodes ($ expr , $ expr ->stmts , $ closureScope , $ closureStmtsCallback );
3171
+ $ statementResult = $ this ->processStmtNodes ($ expr , $ expr ->stmts , $ closureScope , $ closureStmtsCallback, StatementContext:: createTopLevel () );
3153
3172
$ nodeCallback (new ClosureReturnStatementsNode (
3154
3173
$ expr ,
3155
3174
$ gatheredReturnStatements ,
@@ -3165,7 +3184,7 @@ private function processClosureNode(
3165
3184
$ prevScope = $ closureScope ;
3166
3185
3167
3186
$ intermediaryClosureScopeResult = $ this ->processStmtNodes ($ expr , $ expr ->stmts , $ closureScope , static function (): void {
3168
- });
3187
+ }, StatementContext:: createTopLevel () );
3169
3188
$ intermediaryClosureScope = $ intermediaryClosureScopeResult ->getScope ();
3170
3189
foreach ($ intermediaryClosureScopeResult ->getExitPoints () as $ exitPoint ) {
3171
3190
$ intermediaryClosureScope = $ intermediaryClosureScope ->mergeWith ($ exitPoint ->getScope ());
@@ -3181,7 +3200,7 @@ private function processClosureNode(
3181
3200
$ count ++;
3182
3201
} while ($ count < self ::LOOP_SCOPE_ITERATIONS );
3183
3202
3184
- $ statementResult = $ this ->processStmtNodes ($ expr , $ expr ->stmts , $ closureScope , $ closureStmtsCallback );
3203
+ $ statementResult = $ this ->processStmtNodes ($ expr , $ expr ->stmts , $ closureScope , $ closureStmtsCallback, StatementContext:: createTopLevel () );
3185
3204
$ nodeCallback (new ClosureReturnStatementsNode (
3186
3205
$ expr ,
3187
3206
$ gatheredReturnStatements ,
@@ -4101,7 +4120,7 @@ private function processNodesForTraitUse($node, ClassReflection $traitReflection
4101
4120
$ methodAst ->flags = ($ methodAst ->flags & ~ Node \Stmt \Class_::VISIBILITY_MODIFIER_MASK ) | $ methodModifiers [$ methodName ];
4102
4121
$ stmts [$ i ] = $ methodAst ;
4103
4122
}
4104
- $ this ->processStmtNodes ($ node , $ stmts , $ scope ->enterTrait ($ traitReflection ), $ nodeCallback );
4123
+ $ this ->processStmtNodes ($ node , $ stmts , $ scope ->enterTrait ($ traitReflection ), $ nodeCallback, StatementContext:: createTopLevel () );
4105
4124
return ;
4106
4125
}
4107
4126
if ($ node instanceof Node \Stmt \ClassLike) {
0 commit comments