Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

$accessProperty = function (): void {
$reflectionProperty = new ReflectionProperty('Foo', 'bar');
$reflectionProperty->setAccessible(true);
$reflectionProperty->getValue();
};

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

$accessProperty = function (): void {
$reflectionProperty = new ReflectionProperty('Foo', 'bar');
$reflectionProperty->getValue();
};

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

final class InsideIfCondition
{
public function run(bool $flag): void
{
$reflectionProperty = new ReflectionProperty('Foo', 'bar');

if ($flag) {
$reflectionProperty->setAccessible(true);
$reflectionProperty->getValue($this);
}
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

final class InsideIfCondition
{
public function run(bool $flag): void
{
$reflectionProperty = new ReflectionProperty('Foo', 'bar');

if ($flag) {
$reflectionProperty->getValue($this);
}
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

final class SkipMethodCallCaller
{
public function run(): void
{
$this->getReflectionProperty()->setAccessible(true);
}

private function getReflectionProperty(): ReflectionProperty
{
return new ReflectionProperty('Foo', 'bar');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

final class SkipNonReflectionObject
{
public function run(): void
{
$service = new \stdClass();
$service->setAccessible(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

final class SkipUntypedParam
{
public function run($reflectionProperty): void
{
$reflectionProperty->setAccessible(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionMethod;

function standaloneReflectionCall(): void
{
$reflectionMethod = new ReflectionMethod('Foo', 'bar');
$reflectionMethod->setAccessible(true);
$reflectionMethod->invoke(null);
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionMethod;

function standaloneReflectionCall(): void
{
$reflectionMethod = new ReflectionMethod('Foo', 'bar');
$reflectionMethod->invoke(null);
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

final class TypedParam
{
public function run(ReflectionProperty $reflectionProperty): void
{
$reflectionProperty->setAccessible(true);
$reflectionProperty->getValue();
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\Fixture;

use ReflectionProperty;

final class TypedParam
{
public function run(ReflectionProperty $reflectionProperty): void
{
$reflectionProperty->getValue();
}
}

?>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Expression;
use PhpParser\NodeVisitor;
use PHPStan\Type\ObjectType;
use Rector\Analyzer\SimpleScope\SimpleScope;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Rector\AbstractRector;
use Rector\ValueObject\PhpVersion;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
Expand All @@ -18,6 +19,8 @@
/**
* As of PHP 8.1.0, calling `Reflection*::setAccessible()` has no effect.
*
* Caller type comes from the PHPStan-free SimpleScope attached by SimpleScopeNodeVisitor.
*
* @see https://www.php.net/manual/en/reflectionmethod.setaccessible.php
* @see https://www.php.net/manual/en/reflectionproperty.setaccessible.php
* @see \Rector\Tests\Php81\Rector\MethodCall\RemoveReflectionSetAccessibleCallsRector\RemoveReflectionSetAccessibleCallsRectorTest
Expand All @@ -37,23 +40,25 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?int
{
if ($node->expr instanceof MethodCall === false) {
if (! $node->expr instanceof MethodCall) {
return null;
}

$methodCall = $node->expr;
if (! $this->isName($methodCall->name, 'setAccessible')) {
return null;
}

if ($this->isName($methodCall->name, 'setAccessible') === false) {
$simpleScope = $node->getAttribute(AttributeKey::SIMPLE_SCOPE);
if (! $simpleScope instanceof SimpleScope) {
return null;
}

if ($this->isObjectType($methodCall->var, new ObjectType('ReflectionProperty'))
|| $this->isObjectType($methodCall->var, new ObjectType('ReflectionMethod'))
) {
return NodeVisitor::REMOVE_NODE;
if (! $simpleScope->isObjectType($methodCall->var, 'ReflectionProperty', 'ReflectionMethod')) {
return null;
}

return null;
return NodeVisitor::REMOVE_NODE;
}

public function getRuleDefinition(): RuleDefinition
Expand Down
90 changes: 90 additions & 0 deletions src/Analyzer/SimpleScope/SimpleScope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Rector\Analyzer\SimpleScope;

use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\Int_;
use PhpParser\Node\Scalar\String_;
use Rector\Analyzer\SimpleType\ArrayType;
use Rector\Analyzer\SimpleType\BooleanType;
use Rector\Analyzer\SimpleType\Contract\SimpleTypeInterface;
use Rector\Analyzer\SimpleType\IntegerType;
use Rector\Analyzer\SimpleType\MixedType;
use Rector\Analyzer\SimpleType\NullType;
use Rector\Analyzer\SimpleType\ObjectType;
use Rector\Analyzer\SimpleType\StringType;

// PHPStan-free scope; holds variable types resolved by SimpleScopeResolver
final class SimpleScope
{
/**
* @var array<string, SimpleTypeInterface>
*/
private array $variableTypes = [];

public function setVariableType(string $name, SimpleTypeInterface $simpleType): void
{
$this->variableTypes[$name] = $simpleType;
}

public function isObjectType(Expr $expr, string ...$classNames): bool
{
$simpleType = $this->getType($expr);
if (! $simpleType instanceof ObjectType) {
return false;
}

return $simpleType->isInstanceOf(...$classNames);
}

public function getType(Expr $expr): SimpleTypeInterface
{
if ($expr instanceof String_) {
return new StringType();
}

if ($expr instanceof Int_) {
return new IntegerType();
}

if ($expr instanceof Array_) {
return new ArrayType();
}

if ($expr instanceof ConstFetch) {
return $this->resolveConstFetchType($expr);
}

if ($expr instanceof New_ && $expr->class instanceof Name) {
return new ObjectType($expr->class->toString());
}

if ($expr instanceof Variable && is_string($expr->name)) {
return $this->variableTypes[$expr->name] ?? new MixedType();
}

return new MixedType();
}

private function resolveConstFetchType(ConstFetch $constFetch): SimpleTypeInterface
{
$constantName = strtolower($constFetch->name->toString());

if ($constantName === 'null') {
return new NullType();
}

if ($constantName === 'true' || $constantName === 'false') {
return new BooleanType();
}

return new MixedType();
}
}
Loading
Loading