diff --git a/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php b/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php index bb23a48be0f..36bcb7d8b5b 100644 --- a/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php +++ b/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php @@ -110,7 +110,7 @@ public function processNodes( $isScopeRefreshing, $smartFileInfo ): void { - if ($node instanceof Expression) { + if (($node instanceof Expression || $node instanceof Return_) && $node->expr instanceof Expr) { $node->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope); } @@ -140,30 +140,11 @@ public function processNodes( } if ($node instanceof Switch_) { - // decorate value as well - foreach ($node->cases as $case) { - $case->setAttribute(AttributeKey::SCOPE, $mutatingScope); - } + $this->processSwitch($node, $mutatingScope); } if ($node instanceof TryCatch) { - foreach ($node->catches as $catch) { - $varName = $catch->var instanceof Variable - ? $this->nodeNameResolver->getName($catch->var) - : null; - $type = TypeCombinator::union( - ...array_map( - static fn (Name $class): ObjectType => new ObjectType((string) $class), - $catch->types - ) - ); - $catchMutatingScope = $mutatingScope->enterCatchType($type, $varName); - $this->processNodes($catch->stmts, $smartFileInfo, $catchMutatingScope); - } - - if ($node->finally instanceof Finally_) { - $node->finally->setAttribute(AttributeKey::SCOPE, $mutatingScope); - } + $this->processTryCatch($node, $smartFileInfo, $mutatingScope); } if ($node instanceof Assign) { @@ -172,11 +153,6 @@ public function processNodes( $node->var->setAttribute(AttributeKey::SCOPE, $mutatingScope); } - // decorate value as well - if ($node instanceof Return_ && $node->expr instanceof Expr) { - $node->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope); - } - if ($node instanceof Trait_) { $traitName = $this->resolveClassName($node); @@ -207,8 +183,9 @@ public function processNodes( ); $node->setAttribute(AttributeKey::SCOPE, $traitScope); - $this->nodeScopeResolver->processNodes($node->stmts, $traitScope, $nodeCallback); + $this->decorateTraitAttrGroups($node, $traitScope); + return; } @@ -232,6 +209,48 @@ public function processNodes( return $this->processNodesWithDependentFiles($smartFileInfo, $stmts, $scope, $nodeCallback); } + private function decorateTraitAttrGroups(Trait_ $trait, MutatingScope $mutatingScope): void + { + foreach ($trait->attrGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attr) { + foreach ($attr->args as $arg) { + $arg->value->setAttribute(AttributeKey::SCOPE, $mutatingScope); + } + } + } + } + + private function processSwitch(Switch_ $switch, MutatingScope $mutatingScope): void + { + // decorate value as well + foreach ($switch->cases as $case) { + $case->setAttribute(AttributeKey::SCOPE, $mutatingScope); + } + } + + private function processTryCatch( + TryCatch $tryCatch, + SmartFileInfo $smartFileInfo, + MutatingScope $mutatingScope + ): void { + foreach ($tryCatch->catches as $catch) { + $varName = $catch->var instanceof Variable + ? $this->nodeNameResolver->getName($catch->var) + : null; + + $type = TypeCombinator::union( + ...array_map(static fn (Name $class): ObjectType => new ObjectType((string) $class), $catch->types) + ); + + $catchMutatingScope = $mutatingScope->enterCatchType($type, $varName); + $this->processNodes($catch->stmts, $smartFileInfo, $catchMutatingScope); + } + + if ($tryCatch->finally instanceof Finally_) { + $tryCatch->finally->setAttribute(AttributeKey::SCOPE, $mutatingScope); + } + } + private function processUnreachableStatementNode( UnreachableStatementNode $unreachableStatementNode, SmartFileInfo $smartFileInfo, diff --git a/phpstan.neon b/phpstan.neon index 7c15d844005..913069db8b1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -672,3 +672,11 @@ parameters: - message: '#Call to static method Webmozart\\Assert\\Assert\:\:allString\(\) with array will always evaluate to true#' path: rules/Transform/ValueObject/ParentClassToTraits.php + + - + message: '#Relative file path ".+" is not allowed, use absolute one with __DIR__#' + paths: + - bin/rector.php + - src/Bootstrap/RectorConfigsResolver.php + - src/ValueObject/StaticNonPhpFileSuffixes.php + - tests/FileSystem/FilesFinder/FilesFinderTest.php diff --git a/rules-tests/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector/Fixture/skip_attribute_on_trait.php.inc b/rules-tests/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector/Fixture/skip_attribute_on_trait.php.inc new file mode 100644 index 00000000000..5a88b5d15b1 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector/Fixture/skip_attribute_on_trait.php.inc @@ -0,0 +1,10 @@ +