Skip to content

Commit

Permalink
Support NullSafeProperty fetches in unused-code analysis (#5839)
Browse files Browse the repository at this point in the history
* Support NullSafeProperty fetches in unused-code analysis

* fix build
  • Loading branch information
staabm committed Apr 21, 2024
1 parent 4cd2622 commit 71c6dd9
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 9 deletions.
@@ -0,0 +1,16 @@
<?php

namespace Rector\Tests\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector\Fixture;

final class SkipNullSafePropertyFetch
{
private $myProp;

public function pubMethod() {
echo $this->getX()?->myProp;
}

public function getX(): SkipNullSafePropertyFetch|null {
return rand(0,1) ? new SkipNullSafePropertyFetch() : null;
}
}
@@ -0,0 +1,16 @@
<?php

namespace Rector\Tests\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector\Fixture;

final class SkipPrivateOtherProperty
{
private $myProp;

public function pubMethod() {
echo $this->getX()->myProp;
}

public function getX(): self {
return new self();
}
}
@@ -0,0 +1,16 @@
<?php

namespace Rector\Tests\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector\Fixture;

final class SkipNullSafeSelfPropertyFetch
{
private $myProp;

public function pubMethod() {
echo $this->getX()?->myProp;
}

public function getX(): self|null {
return rand(0,1) ? new self() : null;
}
}
5 changes: 3 additions & 2 deletions rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php
Expand Up @@ -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_;
Expand All @@ -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;
}

Expand All @@ -34,7 +35,7 @@ public function hasClassDynamicPropertyNames(Class_ $class): bool
/**
* The property fetches are always only assigned to, nothing else
*
* @param array<PropertyFetch|StaticPropertyFetch> $propertyFetches
* @param array<PropertyFetch|StaticPropertyFetch|NullsafePropertyFetch> $propertyFetches
*/
public function arePropertyFetchesExclusivelyBeingAssignedTo(array $propertyFetches): bool
{
Expand Down
19 changes: 14 additions & 5 deletions src/NodeAnalyzer/PropertyFetchAnalyzer.php
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down
9 changes: 7 additions & 2 deletions src/PhpParser/NodeFinder/PropertyFetchFinder.php
Expand Up @@ -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;
Expand Down Expand Up @@ -70,18 +71,22 @@ 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 {
if ($subNode instanceof PropertyFetch) {
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);
}
Expand Down

0 comments on commit 71c6dd9

Please sign in to comment.