Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"rector/type-perfect": "^2.1",
"shipmonk/composer-dependency-analyser": "^1.8",
"symplify/phpstan-extensions": "^12.0.2",
"symplify/phpstan-rules": "dev-main",
"symplify/phpstan-rules": "^14.9.3",
"symplify/vendor-patches": "^11.5",
"tomasvotruba/class-leak": "^2.1",
"tracy/tracy": "^2.11"
Expand Down
11 changes: 11 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,14 @@ parameters:
-
path: rules/TypeDeclaration/Rector/StmtsAwareInterface/IncreaseDeclareStrictTypesRector.php
identifier: rector.noOnlyNullReturnInRefactor

-
identifier: rector.noIntegerRefactorReturn
paths:
- rules/Transform/Rector/ArrayDimFetch/ArrayDimFetchToMethodCallRector.php

# valid, as use REMOVE_NODE
- rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php
- rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php
- rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php
- rules/DeadCode/Rector/If_/UnwrapFutureCompatibleIfPhpVersionRector.php
25 changes: 17 additions & 8 deletions rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function getNodeTypes(): array

/**
* @param If_ $node
* @return null|int|Stmt[]
* @return null|NodeVisitor::REMOVE_NODE|Stmt[]
*/
public function refactor(Node $node): null|array|int
{
Expand Down Expand Up @@ -112,7 +112,7 @@ public function refactor(Node $node): null|array|int
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorSmaller(ConstFetch $constFetch, Smaller $smaller, If_ $if): null|array|int
{
Expand All @@ -128,7 +128,7 @@ private function refactorSmaller(ConstFetch $constFetch, Smaller $smaller, If_ $
}

/**
* @return null|int|Stmt[]
* @return null|NodeVisitor::REMOVE_NODE|Stmt[]
*/
private function processGreaterOrEqual(
ConstFetch $constFetch,
Expand All @@ -146,6 +146,9 @@ private function processGreaterOrEqual(
return null;
}

/**
* @return null|NodeVisitor::REMOVE_NODE
*/
private function refactorSmallerLeft(Smaller $smaller): ?int
{
$value = $smaller->right;
Expand All @@ -161,7 +164,7 @@ private function refactorSmallerLeft(Smaller $smaller): ?int
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorSmallerRight(Smaller $smaller, If_ $if): null|array|int
{
Expand All @@ -182,7 +185,7 @@ private function refactorSmallerRight(Smaller $smaller, If_ $if): null|array|int
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorGreaterOrEqualLeft(GreaterOrEqual $greaterOrEqual, If_ $if): null|array|int
{
Expand All @@ -202,6 +205,9 @@ private function refactorGreaterOrEqualLeft(GreaterOrEqual $greaterOrEqual, If_
return $if->stmts;
}

/**
* @return NodeVisitor::REMOVE_NODE|null
*/
private function refactorGreaterOrEqualRight(GreaterOrEqual $greaterOrEqual): ?int
{
$value = $greaterOrEqual->left;
Expand All @@ -217,7 +223,7 @@ private function refactorGreaterOrEqualRight(GreaterOrEqual $greaterOrEqual): ?i
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorGreater(ConstFetch $constFetch, Greater $greater, If_ $if): null|array|int
{
Expand All @@ -233,7 +239,7 @@ private function refactorGreater(ConstFetch $constFetch, Greater $greater, If_ $
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorGreaterLeft(Greater $greater, If_ $if): null|array|int
{
Expand All @@ -253,6 +259,9 @@ private function refactorGreaterLeft(Greater $greater, If_ $if): null|array|int
return $if->stmts;
}

/**
* @return NodeVisitor::REMOVE_NODE|null
*/
private function refactorGreaterRight(Greater $greater): ?int
{
$value = $greater->left;
Expand All @@ -268,7 +277,7 @@ private function refactorGreaterRight(Greater $greater): ?int
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorConstFetch(ConstFetch $constFetch, If_ $if, BinaryOp $binaryOp): null|array|int
{
Expand Down
5 changes: 4 additions & 1 deletion rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function getNodeTypes(): array

/**
* @param Expression $node
* @return Node[]|Node|null|int
* @return Node[]|Node|null|NodeVisitor::REMOVE_NODE
*/
public function refactor(Node $node): array|Node|null|int
{
Expand Down Expand Up @@ -106,6 +106,9 @@ private function hasGetMagic(Expression $expression): bool
return ! $phpPropertyReflection instanceof PhpPropertyReflection;
}

/**
* @return NodeVisitor::REMOVE_NODE|Node
*/
private function removeNodeAndKeepComments(Expression $expression): int|Node
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($expression);
Expand Down
4 changes: 2 additions & 2 deletions rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function getNodeTypes(): array

/**
* @param If_ $node
* @return Stmt[]|null|int|If_
* @return Stmt[]|null|NodeVisitor::REMOVE_NODE|If_
*/
public function refactor(Node $node): array|null|int|If_
{
Expand All @@ -98,7 +98,7 @@ public function refactor(Node $node): array|null|int|If_
}

/**
* @return null|Stmt[]|int
* @return null|Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorStmtAndInstanceof(If_ $if, Instanceof_ $instanceof): null|array|int
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function getNodeTypes(): array

/**
* @param If_ $node
* @return Stmt[]|null|int
* @return Stmt[]|null|NodeVisitor::REMOVE_NODE
*/
public function refactor(Node $node): array|int|null
{
Expand Down Expand Up @@ -104,7 +104,7 @@ private function refactorIsMatch(If_ $if): ?array
}

/**
* @return Stmt[]|int
* @return Stmt[]|NodeVisitor::REMOVE_NODE
*/
private function refactorIsNotMatch(If_ $if): array|int
{
Expand Down
51 changes: 24 additions & 27 deletions rules/Renaming/Rector/Name/RenameClassRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
namespace Rector\Renaming\Rector\Name;

use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeVisitor;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Configuration\RenamedClassesDataCollector;
use Rector\Contract\Rector\ConfigurableRectorInterface;
Expand Down Expand Up @@ -80,7 +77,6 @@ function someFunction(SomeNewClass $someOldClass): SomeNewClass
public function getNodeTypes(): array
{
return [
ClassConstFetch::class,
// place FullyQualified before Name on purpose executed early before the Name as parent
FullyQualified::class,
// Name as parent of FullyQualified executed later for fallback annotation to attribute rename to Name
Expand All @@ -94,19 +90,21 @@ public function getNodeTypes(): array
}

/**
* @param ClassConstFetch|FunctionLike|FullyQualified|Name|ClassLike|Expression|Property|If_ $node
* @return null|NodeVisitor::DONT_TRAVERSE_CHILDREN|Node
* @param FunctionLike|FullyQualified|Name|ClassLike|Expression|Property|If_ $node
*/
public function refactor(Node $node): int|null|Node
public function refactor(Node $node): ?Node
{
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();

if ($oldToNewClasses === []) {
return null;
}

if ($node instanceof ClassConstFetch) {
return $this->processClassConstFetch($node, $oldToNewClasses);
if ($node instanceof FullyQualified && $this->shouldSkipClassConstFetchForMissingConstantName(
$node,
$oldToNewClasses
)) {
return null;
}

$scope = $node->getAttribute(AttributeKey::SCOPE);
Expand All @@ -126,18 +124,23 @@ public function configure(array $configuration): void

/**
* @param array<string, string> $oldToNewClasses
* @return null|NodeVisitor::DONT_TRAVERSE_CHILDREN
*/
private function processClassConstFetch(ClassConstFetch $classConstFetch, array $oldToNewClasses): int|null
{
if (! $classConstFetch->class instanceof FullyQualified
|| ! $classConstFetch->name instanceof Identifier
|| ! $this->reflectionProvider->hasClass($classConstFetch->class->toString())) {
return null;
private function shouldSkipClassConstFetchForMissingConstantName(
FullyQualified $fullyQualified,
array $oldToNewClasses
): bool {
if (! $this->reflectionProvider->hasClass($fullyQualified->toString())) {
return false;
}

// not part of class const fetch (e.g. SomeClass::SOME_VALUE)
$constFetchName = $fullyQualified->getAttribute(AttributeKey::CLASS_CONST_FETCH_NAME);
if (! is_string($constFetchName)) {
return false;
}

foreach ($oldToNewClasses as $oldClass => $newClass) {
if (! $this->isName($classConstFetch->class, $oldClass)) {
if (! $this->isName($fullyQualified, $oldClass)) {
continue;
}

Expand All @@ -146,20 +149,14 @@ private function processClassConstFetch(ClassConstFetch $classConstFetch, array
}

$classReflection = $this->reflectionProvider->getClass($newClass);
if (! $classReflection->isInterface()) {
continue;
}

$oldClassReflection = $this->reflectionProvider->getClass($oldClass);

if ($oldClassReflection->hasConstant($classConstFetch->name->toString())
&& ! $classReflection->hasConstant($classConstFetch->name->toString())) {
// no constant found on new interface? skip node below ClassConstFetch on this rule
return NodeVisitor::DONT_TRAVERSE_CHILDREN;
if ($oldClassReflection->hasConstant($constFetchName) && ! $classReflection->hasConstant($constFetchName)) {
// should be skipped as new class does not have access to the constant
return true;
}
}

// continue to next Name usage
return null;
return false;
}
}
2 changes: 2 additions & 0 deletions src/DependencyInjection/LazyContainerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\AssignedToNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ByRefReturnNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ByRefVariableNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ClassConstFetchNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ContextNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\GlobalVariableNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\NameNodeVisitor;
Expand Down Expand Up @@ -247,6 +248,7 @@ final class LazyContainerFactory
NameNodeVisitor::class,
StaticVariableNodeVisitor::class,
PropertyOrClassConstDefaultNodeVisitor::class,
ClassConstFetchNodeVisitor::class,
];

/**
Expand Down
2 changes: 2 additions & 0 deletions src/NodeTypeResolver/Node/AttributeKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,6 @@ final class AttributeKey
public const IS_INSIDE_SYMFONY_PHP_CLOSURE = 'is_inside_symfony_php_closure';

public const IS_INSIDE_BYREF_FUNCTION_LIKE = 'is_inside_byref_function_like';

public const CLASS_CONST_FETCH_NAME = 'class_const_fetch_name';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor;

use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Identifier;
use PhpParser\NodeVisitorAbstract;
use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;

final class ClassConstFetchNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface
{
public function enterNode(Node $node): ?Node
{
if (! $node instanceof ClassConstFetch) {
return null;
}

// pass value metadata to class node
if (! $node->name instanceof Identifier) {
return null;
}

$node->class->setAttribute(AttributeKey::CLASS_CONST_FETCH_NAME, $node->name->toString());

return null;
}
}