Skip to content

Commit

Permalink
Set the correct method visibility when entering the method in regard …
Browse files Browse the repository at this point in the history
…to trait adaptation
  • Loading branch information
ondrejmirtes committed Sep 20, 2021
1 parent 9e15783 commit c524c4e
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
38 changes: 33 additions & 5 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3649,21 +3649,49 @@ 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);
}
}

/**
* @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) {
Expand All @@ -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);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'], []);
}

}
20 changes: 20 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug-4516.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Bug4516;

interface RecordsMessages
{
public function record($message): void;
}

trait PrivateMessageRecorderCapabilities
{
protected function record($message): void
{
}
}

class PublicMessageRecorder implements RecordsMessages
{
use PrivateMessageRecorderCapabilities { record as public; }
}

0 comments on commit c524c4e

Please sign in to comment.