From c524c4e134c547a6ac4d6db9989a37c5ee303489 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 20 Sep 2021 11:49:42 +0200 Subject: [PATCH] Set the correct method visibility when entering the method in regard to trait adaptation --- src/Analyser/NodeScopeResolver.php | 38 ++++++++++++++++--- .../Methods/OverridingMethodRuleTest.php | 6 +++ tests/PHPStan/Rules/Methods/data/bug-4516.php | 20 ++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 tests/PHPStan/Rules/Methods/data/bug-4516.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 89187d27ac..c95ef3eef7 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3649,7 +3649,7 @@ private function processTraitUse(Node\Stmt\TraitUse $node, MutatingScope $classS continue; } $parserNodes = $this->parser->parseFile($fileName); - $this->processNodesForTraitUse($parserNodes, $traitReflection, $classScope, $nodeCallback); + $this->processNodesForTraitUse($parserNodes, $traitReflection, $classScope, $node->adaptations, $nodeCallback); } } @@ -3657,13 +3657,41 @@ private function processTraitUse(Node\Stmt\TraitUse $node, MutatingScope $classS * @param \PhpParser\Node[]|\PhpParser\Node|scalar $node * @param ClassReflection $traitReflection * @param \PHPStan\Analyser\MutatingScope $scope + * @param Node\Stmt\TraitUseAdaptation[] $adaptations * @param callable(\PhpParser\Node $node, Scope $scope): void $nodeCallback */ - private function processNodesForTraitUse($node, ClassReflection $traitReflection, MutatingScope $scope, callable $nodeCallback): void + private function processNodesForTraitUse($node, ClassReflection $traitReflection, MutatingScope $scope, array $adaptations, callable $nodeCallback): void { if ($node instanceof Node) { if ($node instanceof Node\Stmt\Trait_ && $traitReflection->getName() === (string) $node->namespacedName && $traitReflection->getNativeReflection()->getStartLine() === $node->getStartLine()) { - $this->processStmtNodes($node, $node->stmts, $scope->enterTrait($traitReflection), $nodeCallback); + $methodModifiers = []; + foreach ($adaptations as $adaptation) { + if (!$adaptation instanceof Node\Stmt\TraitUseAdaptation\Alias) { + continue; + } + + if ($adaptation->newModifier === null) { + continue; + } + + $methodModifiers[$adaptation->method->toLowerString()] = $adaptation->newModifier; + } + + $stmts = $node->stmts; + foreach ($stmts as $i => $stmt) { + if (!$stmt instanceof Node\Stmt\ClassMethod) { + continue; + } + $methodName = $stmt->name->toLowerString(); + if (!array_key_exists($methodName, $methodModifiers)) { + continue; + } + + $methodAst = clone $stmt; + $methodAst->flags = ($methodAst->flags & ~ Node\Stmt\Class_::VISIBILITY_MODIFIER_MASK) | $methodModifiers[$methodName]; + $stmts[$i] = $methodAst; + } + $this->processStmtNodes($node, $stmts, $scope->enterTrait($traitReflection), $nodeCallback); return; } if ($node instanceof Node\Stmt\ClassLike) { @@ -3674,11 +3702,11 @@ private function processNodesForTraitUse($node, ClassReflection $traitReflection } foreach ($node->getSubNodeNames() as $subNodeName) { $subNode = $node->{$subNodeName}; - $this->processNodesForTraitUse($subNode, $traitReflection, $scope, $nodeCallback); + $this->processNodesForTraitUse($subNode, $traitReflection, $scope, $adaptations, $nodeCallback); } } elseif (is_array($node)) { foreach ($node as $subNode) { - $this->processNodesForTraitUse($subNode, $traitReflection, $scope, $nodeCallback); + $this->processNodesForTraitUse($subNode, $traitReflection, $scope, $adaptations, $nodeCallback); } } } diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index 06083ccdf0..939caa2cd4 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -510,4 +510,10 @@ public function testParameterTypeWidening(int $phpVersionId, array $errors): voi $this->analyse([__DIR__ . '/data/parameter-type-widening.php'], $errors); } + public function testBug4516(): void + { + $this->phpVersionId = PHP_VERSION_ID; + $this->analyse([__DIR__ . '/data/bug-4516.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-4516.php b/tests/PHPStan/Rules/Methods/data/bug-4516.php new file mode 100644 index 0000000000..df3b34a4c7 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-4516.php @@ -0,0 +1,20 @@ +