From 71c6dd929f07d6491847ee9004224441265d0197 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 21 Apr 2024 21:22:37 +0200 Subject: [PATCH] Support NullSafeProperty fetches in unused-code analysis (#5839) * Support NullSafeProperty fetches in unused-code analysis * fix build --- .../Fixture/skip_nullsafe_property.php.inc | 16 ++++++++++++++++ .../Fixture/skip_other_property.php.inc | 16 ++++++++++++++++ .../skip_self_nullsafe_property.php.inc | 16 ++++++++++++++++ .../PropertyWriteonlyAnalyzer.php | 5 +++-- src/NodeAnalyzer/PropertyFetchAnalyzer.php | 19 ++++++++++++++----- .../NodeFinder/PropertyFetchFinder.php | 9 +++++++-- 6 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_nullsafe_property.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_other_property.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_self_nullsafe_property.php.inc diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_nullsafe_property.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_nullsafe_property.php.inc new file mode 100644 index 00000000000..5f09c36c722 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_nullsafe_property.php.inc @@ -0,0 +1,16 @@ +getX()?->myProp; + } + + public function getX(): SkipNullSafePropertyFetch|null { + return rand(0,1) ? new SkipNullSafePropertyFetch() : null; + } +} diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_other_property.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_other_property.php.inc new file mode 100644 index 00000000000..331a0dfc496 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_other_property.php.inc @@ -0,0 +1,16 @@ +getX()->myProp; + } + + public function getX(): self { + return new self(); + } +} diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_self_nullsafe_property.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_self_nullsafe_property.php.inc new file mode 100644 index 00000000000..6a0a25893d7 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/skip_self_nullsafe_property.php.inc @@ -0,0 +1,16 @@ +getX()?->myProp; + } + + public function getX(): self|null { + return rand(0,1) ? new self() : null; + } +} diff --git a/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php b/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php index 3c144e17409..2d21cf6530a 100644 --- a/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php +++ b/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Expr; +use PhpParser\Node\Expr\NullsafePropertyFetch; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticPropertyFetch; use PhpParser\Node\Stmt\Class_; @@ -22,7 +23,7 @@ public function __construct( public function hasClassDynamicPropertyNames(Class_ $class): bool { return (bool) $this->betterNodeFinder->findFirst($class, static function (Node $node): bool { - if (! $node instanceof PropertyFetch) { + if (! $node instanceof PropertyFetch && !$node instanceof NullsafePropertyFetch) { return false; } @@ -34,7 +35,7 @@ public function hasClassDynamicPropertyNames(Class_ $class): bool /** * The property fetches are always only assigned to, nothing else * - * @param array $propertyFetches + * @param array $propertyFetches */ public function arePropertyFetchesExclusivelyBeingAssignedTo(array $propertyFetches): bool { diff --git a/src/NodeAnalyzer/PropertyFetchAnalyzer.php b/src/NodeAnalyzer/PropertyFetchAnalyzer.php index c58c1472c95..f75c93721a7 100644 --- a/src/NodeAnalyzer/PropertyFetchAnalyzer.php +++ b/src/NodeAnalyzer/PropertyFetchAnalyzer.php @@ -7,6 +7,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\NullsafePropertyFetch; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\StaticPropertyFetch; @@ -46,13 +47,17 @@ public function __construct( public function isLocalPropertyFetch(Node $node): bool { - if (! $node instanceof PropertyFetch && ! $node instanceof StaticPropertyFetch) { + if ( + ! $node instanceof PropertyFetch + && ! $node instanceof StaticPropertyFetch + && ! $node instanceof NullsafePropertyFetch + ) { return false; } - $variableType = $node instanceof PropertyFetch - ? $this->nodeTypeResolver->getType($node->var) - : $this->nodeTypeResolver->getType($node->class); + $variableType = $node instanceof StaticPropertyFetch + ? $this->nodeTypeResolver->getType($node->class) + : $this->nodeTypeResolver->getType($node->var); if ($variableType instanceof ObjectType) { $classReflection = $this->reflectionResolver->resolveClassReflection($node); @@ -72,7 +77,11 @@ public function isLocalPropertyFetch(Node $node): bool public function isLocalPropertyFetchName(Node $node, string $desiredPropertyName): bool { - if (! $node instanceof PropertyFetch && ! $node instanceof StaticPropertyFetch) { + if ( + ! $node instanceof PropertyFetch + && ! $node instanceof StaticPropertyFetch + && ! $node instanceof NullsafePropertyFetch + ) { return false; } diff --git a/src/PhpParser/NodeFinder/PropertyFetchFinder.php b/src/PhpParser/NodeFinder/PropertyFetchFinder.php index 2272658fac5..eabe28574f5 100644 --- a/src/PhpParser/NodeFinder/PropertyFetchFinder.php +++ b/src/PhpParser/NodeFinder/PropertyFetchFinder.php @@ -10,6 +10,7 @@ use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\NullsafePropertyFetch; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\StaticPropertyFetch; @@ -70,11 +71,11 @@ public function findPrivatePropertyFetches( } /** - * @return PropertyFetch[]|StaticPropertyFetch[] + * @return PropertyFetch[]|StaticPropertyFetch[]|NullsafePropertyFetch[] */ public function findLocalPropertyFetchesByName(Class_ $class, string $paramName): array { - /** @var PropertyFetch[]|StaticPropertyFetch[] $foundPropertyFetches */ + /** @var PropertyFetch[]|StaticPropertyFetch[]|NullsafePropertyFetch[] $foundPropertyFetches */ $foundPropertyFetches = $this->betterNodeFinder->find( $class->getMethods(), function (Node $subNode) use ($paramName): bool { @@ -82,6 +83,10 @@ function (Node $subNode) use ($paramName): bool { return $this->propertyFetchAnalyzer->isLocalPropertyFetchName($subNode, $paramName); } + if ($subNode instanceof NullsafePropertyFetch) { + return $this->propertyFetchAnalyzer->isLocalPropertyFetchName($subNode, $paramName); + } + if ($subNode instanceof StaticPropertyFetch) { return $this->propertyFetchAnalyzer->isLocalPropertyFetchName($subNode, $paramName); }