From 32ca3407702146d3f84a2bfe5c3976206b023568 Mon Sep 17 00:00:00 2001 From: Brad <28307684+mad-briller@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:10:29 +0100 Subject: [PATCH 1/2] Set class and method reflection in the MethodReturnStatementNode. --- src/Analyser/NodeScopeResolver.php | 16 +++++++++++----- src/Node/MethodReturnStatementsNode.php | 14 ++++++++++++++ ...MissingCheckedExceptionInMethodThrowsRule.php | 7 +------ ...hrowsVoidMethodWithExplicitThrowPointRule.php | 7 +------ .../Exceptions/TooWideMethodThrowTypeRule.php | 15 +++------------ src/Rules/Playground/MethodNeverRule.php | 7 +------ .../TooWideMethodReturnTypehintRule.php | 7 +------ 7 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index b69e02a10b..ae2abf3cdf 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -595,12 +595,22 @@ private function processStmtNode( $gatheredReturnStatements[] = new ReturnStatement($scope, $node); }, StatementContext::createTopLevel()); + + $classReflection = $scope->getClassReflection(); + + $methodReflection = $methodScope->getFunction(); + if (!$methodReflection instanceof MethodReflection) { + throw new ShouldNotHappenException(); + } + $nodeCallback(new MethodReturnStatementsNode( $stmt, $gatheredReturnStatements, $gatheredYieldStatements, $statementResult, $executionEnds, + $classReflection, + $methodReflection, ), $methodScope); } } elseif ($stmt instanceof Echo_) { @@ -4423,11 +4433,7 @@ private function processCalledMethod(MethodReflection $methodReflection): ?Mutat return; } - if (!$scope->isInClass()) { - return; - } - - if ($scope->getClassReflection()->getName() !== $methodReflection->getDeclaringClass()->getName()) { + if ($node->getClassReflection()->getName() !== $methodReflection->getDeclaringClass()->getName()) { return; } diff --git a/src/Node/MethodReturnStatementsNode.php b/src/Node/MethodReturnStatementsNode.php index fc39507c05..fe7aa691fb 100644 --- a/src/Node/MethodReturnStatementsNode.php +++ b/src/Node/MethodReturnStatementsNode.php @@ -7,6 +7,8 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\NodeAbstract; use PHPStan\Analyser\StatementResult; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\MethodReflection; use function count; /** @api */ @@ -26,6 +28,8 @@ public function __construct( private array $yieldStatements, private StatementResult $statementResult, private array $executionEnds, + private ClassReflection $classReflection, + private MethodReflection $methodReflection, ) { parent::__construct($method->getAttributes()); @@ -67,6 +71,16 @@ public function getYieldStatements(): array return $this->yieldStatements; } + public function getClassReflection(): ClassReflection + { + return $this->classReflection; + } + + public function getMethodReflection(): MethodReflection + { + return $this->methodReflection; + } + public function isGenerator(): bool { return count($this->yieldStatements) > 0; diff --git a/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php b/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php index 40a398e25e..02e72dccb9 100644 --- a/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php +++ b/src/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRule.php @@ -5,10 +5,8 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\MethodReturnStatementsNode; -use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use function sprintf; /** @@ -29,10 +27,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $statementResult = $node->getStatementResult(); - $methodReflection = $scope->getFunction(); - if (!$methodReflection instanceof MethodReflection) { - throw new ShouldNotHappenException(); - } + $methodReflection = $node->getMethodReflection(); $errors = []; foreach ($this->check->check($methodReflection->getThrowType(), $statementResult->getThrowPoints()) as [$className, $throwPointNode]) { diff --git a/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php b/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php index 9839b49ea1..0e6080eff9 100644 --- a/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php +++ b/src/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRule.php @@ -5,10 +5,8 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\MethodReturnStatementsNode; -use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\TypeUtils; use PHPStan\Type\VerbosityLevel; @@ -35,10 +33,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $statementResult = $node->getStatementResult(); - $methodReflection = $scope->getFunction(); - if (!$methodReflection instanceof MethodReflection) { - throw new ShouldNotHappenException(); - } + $methodReflection = $node->getMethodReflection(); if ($methodReflection->getThrowType() === null || !$methodReflection->getThrowType()->isVoid()->yes()) { return []; diff --git a/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php b/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php index 3a26b6843e..94bd6427ca 100644 --- a/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php +++ b/src/Rules/Exceptions/TooWideMethodThrowTypeRule.php @@ -5,10 +5,8 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\MethodReturnStatementsNode; -use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use PHPStan\Type\FileTypeMapper; use function sprintf; @@ -29,21 +27,14 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $statementResult = $node->getStatementResult(); - $methodReflection = $scope->getFunction(); - if (!$methodReflection instanceof MethodReflection) { - throw new ShouldNotHappenException(); - } - if (!$scope->isInClass()) { - throw new ShouldNotHappenException(); - } - $docComment = $node->getDocComment(); if ($docComment === null) { return []; } - $classReflection = $scope->getClassReflection(); + $statementResult = $node->getStatementResult(); + $methodReflection = $node->getMethodReflection(); + $classReflection = $node->getClassReflection(); $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( $scope->getFile(), $classReflection->getName(), diff --git a/src/Rules/Playground/MethodNeverRule.php b/src/Rules/Playground/MethodNeverRule.php index 7bba0df997..443a31112f 100644 --- a/src/Rules/Playground/MethodNeverRule.php +++ b/src/Rules/Playground/MethodNeverRule.php @@ -5,11 +5,9 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\MethodReturnStatementsNode; -use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use function count; use function sprintf; @@ -34,10 +32,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $method = $scope->getFunction(); - if (!$method instanceof MethodReflection) { - throw new ShouldNotHappenException(); - } + $method = $node->getMethodReflection(); $returnType = ParametersAcceptorSelector::selectSingle($method->getVariants())->getReturnType(); $helperResult = $this->helper->shouldReturnNever($node, $returnType); diff --git a/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php b/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php index c851cbf2ae..cb14c72c2f 100644 --- a/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php +++ b/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php @@ -5,11 +5,9 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\MethodReturnStatementsNode; -use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\TypeCombinator; use PHPStan\Type\UnionType; @@ -34,10 +32,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - $method = $scope->getFunction(); - if (!$method instanceof MethodReflection) { - throw new ShouldNotHappenException(); - } + $method = $node->getMethodReflection(); $isFirstDeclaration = $method->getPrototype()->getDeclaringClass() === $method->getDeclaringClass(); if (!$method->isPrivate()) { if (!$this->checkProtectedAndPublicMethods) { From 6d08225af80480dc133f5f02c2e392cfe8e2921f Mon Sep 17 00:00:00 2001 From: Brad <28307684+mad-briller@users.noreply.github.com> Date: Sat, 8 Jul 2023 12:13:23 +0100 Subject: [PATCH 2/2] Simplify access to class reflections in ClassConstantsNode and ClassMethodsNode rules. --- src/Analyser/NodeScopeResolver.php | 4 ++-- src/Node/ClassConstantsNode.php | 8 +++++++- src/Node/ClassMethodsNode.php | 8 +++++++- src/Rules/DeadCode/UnusedPrivateConstantRule.php | 6 +----- src/Rules/DeadCode/UnusedPrivateMethodRule.php | 6 +----- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index ae2abf3cdf..3b1d68d9b7 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -706,8 +706,8 @@ private function processStmtNode( $this->processStmtNodes($stmt, $stmt->stmts, $classScope, $classStatementsGatherer, $context); $nodeCallback(new ClassPropertiesNode($stmt, $this->readWritePropertiesExtensionProvider, $classStatementsGatherer->getProperties(), $classStatementsGatherer->getPropertyUsages(), $classStatementsGatherer->getMethodCalls(), $classStatementsGatherer->getReturnStatementsNodes(), $classReflection), $classScope); - $nodeCallback(new ClassMethodsNode($stmt, $classStatementsGatherer->getMethods(), $classStatementsGatherer->getMethodCalls()), $classScope); - $nodeCallback(new ClassConstantsNode($stmt, $classStatementsGatherer->getConstants(), $classStatementsGatherer->getConstantFetches()), $classScope); + $nodeCallback(new ClassMethodsNode($stmt, $classStatementsGatherer->getMethods(), $classStatementsGatherer->getMethodCalls(), $classReflection), $classScope); + $nodeCallback(new ClassConstantsNode($stmt, $classStatementsGatherer->getConstants(), $classStatementsGatherer->getConstantFetches(), $classReflection), $classScope); $classReflection->evictPrivateSymbols(); $this->calledMethodResults = []; } elseif ($stmt instanceof Node\Stmt\Property) { diff --git a/src/Node/ClassConstantsNode.php b/src/Node/ClassConstantsNode.php index 4572ff79eb..dee7d0019a 100644 --- a/src/Node/ClassConstantsNode.php +++ b/src/Node/ClassConstantsNode.php @@ -6,6 +6,7 @@ use PhpParser\Node\Stmt\ClassLike; use PhpParser\NodeAbstract; use PHPStan\Node\Constant\ClassConstantFetch; +use PHPStan\Reflection\ClassReflection; /** @api */ class ClassConstantsNode extends NodeAbstract implements VirtualNode @@ -15,7 +16,7 @@ class ClassConstantsNode extends NodeAbstract implements VirtualNode * @param ClassConst[] $constants * @param ClassConstantFetch[] $fetches */ - public function __construct(private ClassLike $class, private array $constants, private array $fetches) + public function __construct(private ClassLike $class, private array $constants, private array $fetches, private ClassReflection $classReflection) { parent::__construct($class->getAttributes()); } @@ -54,4 +55,9 @@ public function getSubNodeNames(): array return []; } + public function getClassReflection(): ClassReflection + { + return $this->classReflection; + } + } diff --git a/src/Node/ClassMethodsNode.php b/src/Node/ClassMethodsNode.php index 0b5c616c34..e02620532b 100644 --- a/src/Node/ClassMethodsNode.php +++ b/src/Node/ClassMethodsNode.php @@ -5,6 +5,7 @@ use PhpParser\Node\Stmt\ClassLike; use PhpParser\NodeAbstract; use PHPStan\Node\Method\MethodCall; +use PHPStan\Reflection\ClassReflection; /** @api */ class ClassMethodsNode extends NodeAbstract implements VirtualNode @@ -14,7 +15,7 @@ class ClassMethodsNode extends NodeAbstract implements VirtualNode * @param ClassMethod[] $methods * @param array $methodCalls */ - public function __construct(private ClassLike $class, private array $methods, private array $methodCalls) + public function __construct(private ClassLike $class, private array $methods, private array $methodCalls, private ClassReflection $classReflection) { parent::__construct($class->getAttributes()); } @@ -53,4 +54,9 @@ public function getSubNodeNames(): array return []; } + public function getClassReflection(): ClassReflection + { + return $this->classReflection; + } + } diff --git a/src/Rules/DeadCode/UnusedPrivateConstantRule.php b/src/Rules/DeadCode/UnusedPrivateConstantRule.php index 814f8402e8..024cbbf322 100644 --- a/src/Rules/DeadCode/UnusedPrivateConstantRule.php +++ b/src/Rules/DeadCode/UnusedPrivateConstantRule.php @@ -8,7 +8,6 @@ use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtensionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use function sprintf; /** @@ -31,11 +30,8 @@ public function processNode(Node $node, Scope $scope): array if (!$node->getClass() instanceof Node\Stmt\Class_ && !$node->getClass() instanceof Node\Stmt\Enum_) { return []; } - if (!$scope->isInClass()) { - throw new ShouldNotHappenException(); - } - $classReflection = $scope->getClassReflection(); + $classReflection = $node->getClassReflection(); $constants = []; foreach ($node->getConstants() as $constant) { diff --git a/src/Rules/DeadCode/UnusedPrivateMethodRule.php b/src/Rules/DeadCode/UnusedPrivateMethodRule.php index 5d3eefd71e..83d2f2313f 100644 --- a/src/Rules/DeadCode/UnusedPrivateMethodRule.php +++ b/src/Rules/DeadCode/UnusedPrivateMethodRule.php @@ -9,7 +9,6 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\ShouldNotHappenException; use PHPStan\Type\Constant\ConstantStringType; use function array_map; use function count; @@ -32,10 +31,7 @@ public function processNode(Node $node, Scope $scope): array if (!$node->getClass() instanceof Node\Stmt\Class_ && !$node->getClass() instanceof Node\Stmt\Enum_) { return []; } - if (!$scope->isInClass()) { - throw new ShouldNotHappenException(); - } - $classReflection = $scope->getClassReflection(); + $classReflection = $node->getClassReflection(); $constructor = null; if ($classReflection->hasConstructor()) { $constructor = $classReflection->getConstructor();