Make use of inline parser over extreme node construction (#6145)

Co-authored-by: kaizen-ci <info@kaizen-ci.org>
This commit is contained in:
Tomas Votruba 2021-04-15 19:34:49 +02:00 committed by GitHub
parent a7234e7ac3
commit b8071fb7bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 230 additions and 206 deletions

View File

@ -13,7 +13,6 @@ use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
@ -55,7 +54,7 @@ final class ParsedPropertyFetchNodeCollector
}
// make sure name is valid
if (StaticNodeInstanceOf::isOneOf($node->name, [StaticCall::class, MethodCall::class])) {
if ($node->name instanceof StaticCall || $node->name instanceof MethodCall) {
return;
}

View File

@ -8,10 +8,10 @@ use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PostRector\Contract\Collector\NodeCollectorInterface;
@ -128,10 +128,15 @@ final class NodesToAddCollector implements NodeCollectorInterface
private function resolveNearestExpressionPosition(Node $node): string
{
if (StaticNodeInstanceOf::isOneOf($node, [Expression::class, Stmt::class])) {
if ($node instanceof Expression || $node instanceof Stmt) {
return spl_object_hash($node);
}
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parent instanceof Return_) {
return spl_object_hash($parent);
}
$foundNode = $this->betterNodeFinder->findParentType($node, Expression::class);
if (! $foundNode instanceof Expression) {
$foundNode = $node;

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="tests/bootstrap.php"
colors="true"
>

View File

@ -7,6 +7,5 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(NetteFormToSymfonyFormRector::class);
};

View File

@ -1,22 +1,22 @@
<?php
declare(strict_types=1);
use Rector\Tests\Transform\Rector\Assign\GetAndSetToMethodCallRector\Source\Klarka;
use Rector\Tests\Transform\Rector\Assign\GetAndSetToMethodCallRector\Source\SomeContainer;
use Rector\Transform\Rector\Assign\GetAndSetToMethodCallRector;
use Rector\Transform\ValueObject\GetAndSetToMethodCall;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(GetAndSetToMethodCallRector::class)
->call('configure', [[
GetAndSetToMethodCallRector::TYPE_TO_METHOD_CALLS => [
SomeContainer::class => [
'get' => 'getService',
'set' => 'addService',
],
Klarka::class => [
'get' => 'get',
],
],
GetAndSetToMethodCallRector::TYPE_TO_METHOD_CALLS => ValueObjectInliner::inline([
new GetAndSetToMethodCall(SomeContainer::class, 'getService', 'addService'),
new GetAndSetToMethodCall(Klarka::class, 'get', 'set'),
]),
]]);
};

View File

@ -20,7 +20,6 @@ use PhpParser\Node\Stmt\Unset_;
use Rector\Core\NodeManipulator\AssignManipulator;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -103,9 +102,9 @@ final class ForAnalyzer
return false;
}
/** @var PreInc|PostInc $prePostInc */
$prePostInc = $loopExprs[0];
if (StaticNodeInstanceOf::isOneOf($prePostInc, [PreInc::class, PostInc::class])) {
if ($prePostInc instanceof PreInc || $prePostInc instanceof PostInc) {
return $this->nodeNameResolver->isName($prePostInc->var, $keyValueName);
}

View File

@ -15,7 +15,6 @@ use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\NodeManipulator\ForeachManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -127,7 +126,7 @@ CODE_SAMPLE
}
$innerNode = $node->stmts[0] instanceof Expression ? $node->stmts[0]->expr : $node->stmts[0];
if (StaticNodeInstanceOf::isOneOf($innerNode, [Assign::class, Return_::class])) {
if ($innerNode instanceof Assign || $innerNode instanceof Return_) {
return $innerNode;
}

View File

@ -18,7 +18,6 @@ use PhpParser\Node\Expr\Cast\String_;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -104,7 +103,7 @@ CODE_SAMPLE
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
// result of function or probably used
if (StaticNodeInstanceOf::isOneOf($parentNode, [Expr::class, Arg::class])) {
if ($parentNode instanceof Expr || $parentNode instanceof Arg) {
return null;
}

View File

@ -30,7 +30,6 @@ use PhpParser\Node\Expr\UnaryPlus;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\PostRector\Collector\NodesToAddCollector;
final class LivingCodeManipulator
@ -63,7 +62,7 @@ final class LivingCodeManipulator
return [];
}
if (StaticNodeInstanceOf::isOneOf($expr, [Closure::class, Scalar::class, ConstFetch::class])) {
if ($expr instanceof Closure || $expr instanceof Scalar || $expr instanceof ConstFetch) {
return [];
}
@ -88,8 +87,8 @@ final class LivingCodeManipulator
$this->keepLivingCodeFromExpr($expr->dim)
);
}
if (StaticNodeInstanceOf::isOneOf($expr, [ClassConstFetch::class, StaticPropertyFetch::class])) {
/** @var ClassConstFetch|StaticPropertyFetch $expr */
if ($expr instanceof ClassConstFetch || $expr instanceof StaticPropertyFetch) {
return array_merge(
$this->keepLivingCodeFromExpr($expr->class),
$this->keepLivingCodeFromExpr($expr->name)

View File

@ -15,7 +15,6 @@ use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNestingScope\ScopeNestingComparator;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -100,7 +99,7 @@ CODE_SAMPLE
private function isCall(Expr $expr): bool
{
return StaticNodeInstanceOf::isOneOf($expr, [FuncCall::class, StaticCall::class, MethodCall::class]);
return $expr instanceof FuncCall || $expr instanceof StaticCall || $expr instanceof MethodCall;
}
private function shouldSkipForDifferentScope(Assign $assign, Expression $expression): bool

View File

@ -18,7 +18,6 @@ use PhpParser\Node\Expr\BinaryOp\Mul;
use PhpParser\Node\Expr\BinaryOp\Plus;
use PhpParser\Node\Expr\UnaryMinus;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -139,8 +138,7 @@ CODE_SAMPLE
private function processBinaryOp(Node $node): ?Expr
{
if (StaticNodeInstanceOf::isOneOf($node, [Plus::class, Minus::class])) {
/** @var Plus|Minus $node */
if ($node instanceof Plus || $node instanceof Minus) {
return $this->processBinaryPlusAndMinus($node);
}

View File

@ -16,7 +16,6 @@ use PHPStan\Analyser\MutatingScope;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\Defluent\Reflection\MethodCallToClassMethodParser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -239,7 +238,11 @@ final class FluentChainMethodCallNodeAnalyzer
private function isCall(Expr $expr): bool
{
return StaticNodeInstanceOf::isOneOf($expr, [MethodCall::class, StaticCall::class]);
if ($expr instanceof MethodCall) {
return true;
}
return $expr instanceof StaticCall;
}
private function isMethodCallCreatingNewInstance(MethodCall $methodCall): bool

View File

@ -13,7 +13,6 @@ use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\Defluent\ValueObject\AssignAndRootExpr;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Rector\Naming\Naming\PropertyNaming;
@ -86,7 +85,7 @@ final class FluentChainMethodCallRootExtractor
}
foreach ($methodCalls as $methodCall) {
if (StaticNodeInstanceOf::isOneOf($methodCall->var, [Variable::class, PropertyFetch::class])) {
if ($methodCall->var instanceof Variable || $methodCall->var instanceof PropertyFetch) {
return $this->createAssignAndRootExprForVariableOrPropertyFetch($methodCall);
}
if ($methodCall->var instanceof New_) {

View File

@ -5,26 +5,15 @@ declare(strict_types=1);
namespace Rector\Downgrade72\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp\BitwiseAnd;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\ErrorSuppress;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Parser\InlineCodeParser;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -36,9 +25,14 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class DowngradeStreamIsattyRector extends AbstractRector
{
/**
* @var string
* @var InlineCodeParser
*/
private const STAT = 'stat';
private $inlineCodeParser;
public function __construct(InlineCodeParser $inlineCodeParser)
{
$this->inlineCodeParser = $inlineCodeParser;
}
public function getRuleDefinition(): RuleDefinition
{
@ -92,59 +86,25 @@ CODE_SAMPLE
return null;
}
$function = $this->createClosure($node);
$function = $this->createClosure();
$assign = new Assign(new Variable('streamIsatty'), $function);
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parent instanceof Return_) {
$this->addNodeBeforeNode($assign, $parent);
} else {
$this->addNodeBeforeNode($assign, $node);
}
$this->addNodeBeforeNode($assign, $node);
return new FuncCall(new Variable('streamIsatty'), $node->args);
}
private function createIf(Expr $expr): If_
private function createClosure(): Closure
{
$constFetch = new ConstFetch(new FullyQualified('DIRECTORY_SEPARATOR'));
$identical = new Identical(new String_('\\'), $constFetch);
$stmts = $this->inlineCodeParser->parse(__DIR__ . '/../../snippet/isatty_closure.php.inc');
$if = new If_($identical);
$statAssign = new Assign(
new Variable(self::STAT),
new ErrorSuppress($this->nodeFactory->createFuncCall('fstat', [$expr]))
);
$if->stmts[] = new Expression($statAssign);
/** @var Expression $expression */
$expression = $stmts[0];
$arrayDimFetch = new ArrayDimFetch(new Variable(self::STAT), new String_('mode'));
$bitwiseAnd = new BitwiseAnd(
$arrayDimFetch,
new LNumber(0170000, [
AttributeKey::KIND => LNumber::KIND_OCT,
])
);
$expr = $expression->expr;
if (! $expr instanceof Closure) {
throw new ShouldNotHappenException();
}
$identical = new Identical(new LNumber(020000, [
AttributeKey::KIND => LNumber::KIND_OCT,
]), $bitwiseAnd);
$ternary = new Ternary(new Variable(self::STAT), $identical, $this->nodeFactory->createFalse());
$if->stmts[] = new Return_($ternary);
return $if;
}
private function createClosure(FuncCall $funcCall): Closure
{
$if = $this->createIf($funcCall->args[0]->value);
$function = new Closure();
$function->params[] = new Param(new Variable('stream'));
$function->stmts[] = $if;
$posixIsatty = $this->nodeFactory->createFuncCall('posix_isatty', [$funcCall->args[0]->value]);
$function->stmts[] = new Return_(new ErrorSuppress($posixIsatty));
return $function;
return $expr;
}
}

View File

@ -0,0 +1,9 @@
<?php
function ($stream) {
if ('\\' === \DIRECTORY_SEPARATOR) {
$stat = @fstat($stream);
return $stat ? 020000 === ($stat['mode'] & 0170000) : false;
}
return @posix_isatty($stream);
};

View File

@ -16,7 +16,6 @@ use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\DowngradePhp73\Tokenizer\FollowedByCommaAnalyzer;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -102,12 +101,11 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (StaticNodeInstanceOf::isOneOf($node, [
MethodCall::class,
FuncCall::class,
StaticCall::class,
New_::class,
])) {
if ($node instanceof MethodCall ||
$node instanceof FuncCall ||
$node instanceof StaticCall ||
$node instanceof New_
) {
/** @var MethodCall|FuncCall|StaticCall|New_ $node */
return $this->processArgs($node);
}

View File

@ -22,7 +22,6 @@ use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Stringy\Stringy;
@ -89,9 +88,7 @@ final class VariableNaming
return $this->resolveFromPropertyFetch($node);
}
if ($node !== null && StaticNodeInstanceOf::isOneOf(
$node,
[MethodCall::class, NullsafeMethodCall::class, StaticCall::class])) {
if ($node !== null && ($node instanceof MethodCall || $node instanceof NullsafeMethodCall || $node instanceof StaticCall)) {
return $this->resolveFromMethodCall($node);
}

View File

@ -65,7 +65,6 @@ class SomePresenter extends UI\Presenter
{
$form = new UI\Form;
$form->addText('name', 'Name:');
$form->addPassword('password', 'Password:');
$form->addSubmit('login', 'Sign up');
}
}
@ -82,9 +81,6 @@ class SomePresenter extends UI\Presenter
$form->add('name', \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
'label' => 'Name:'
]);
$form->add('password', \Symfony\Component\Form\Extension\Core\Type\PasswordType::class, [
'label' => 'Password:'
]);
$form->add('login', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, [
'label' => 'Sign up'
]);

View File

@ -27,7 +27,6 @@ use PhpParser\Node\Stmt\Unset_;
use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -213,7 +212,8 @@ CODE_SAMPLE
)) {
return true;
}
if (StaticNodeInstanceOf::isOneOf($parentNode, [Unset_::class, UnsetCast::class])) {
if ($parentNode instanceof Unset_ || $parentNode instanceof UnsetCast) {
return true;
}
@ -252,7 +252,11 @@ CODE_SAMPLE
private function isListAssign(Node $node): bool
{
$parentParentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
return StaticNodeInstanceOf::isOneOf($parentParentNode, [List_::class, Array_::class]);
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof List_) {
return true;
}
return $parentNode instanceof Array_;
}
}

View File

@ -25,7 +25,6 @@ use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Stringy\Stringy;
@ -181,11 +180,7 @@ final class VariableNaming
return $this->resolveFromPropertyFetch($node);
}
if ($node !== null && StaticNodeInstanceOf::isOneOf(
$node,
[MethodCall::class, NullsafeMethodCall::class, StaticCall::class])) {
/** @var MethodCall|NullsafeMethodCall|StaticCall $node */
if ($node instanceof MethodCall || $node instanceof NullsafeMethodCall || $node instanceof StaticCall) {
return $this->resolveFromMethodCall($node);
}

View File

@ -21,7 +21,6 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class RegexDashEscapeRector extends AbstractRector
{
/**
* @var string
* @see https://regex101.com/r/iQbGgZ/1

View File

@ -12,7 +12,6 @@ use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Webmozart\Assert\Assert;
@ -81,7 +80,7 @@ final class IdentifierManipulator
*/
private function resolveOldMethodName(Node $node): ?string
{
if (StaticNodeInstanceOf::isOneOf($node, [StaticCall::class, MethodCall::class])) {
if ($node instanceof StaticCall || $node instanceof MethodCall) {
return $this->nodeNameResolver->getName($node->name);
}

View File

@ -17,7 +17,6 @@ use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\PhpDocTypeRenamer;
use Rector\Renaming\ValueObject\PseudoNamespaceToNamespace;
@ -138,9 +137,7 @@ CODE_SAMPLE
private function refactorStmts(array $stmts): array
{
$this->traverseNodesWithCallable($stmts, function (Node $node): ?Node {
if (! StaticNodeInstanceOf::isOneOf(
$node,
[Name::class, Identifier::class, Property::class, FunctionLike::class])) {
if (! $node instanceof Name && ! $node instanceof Identifier && ! $node instanceof Property && ! $node instanceof FunctionLike) {
return null;
}

View File

@ -9,17 +9,17 @@ use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Variable;
use PHPStan\Type\ObjectType;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\NodeManipulator\MagicPropertyFetchAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Transform\ValueObject\GetAndSetToMethodCall;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Webmozart\Assert\Assert;
/**
* @see \Rector\Tests\Transform\Rector\Assign\GetAndSetToMethodCallRector\GetAndSetToMethodCallRectorTest
@ -32,14 +32,9 @@ final class GetAndSetToMethodCallRector extends AbstractRector implements Config
public const TYPE_TO_METHOD_CALLS = 'type_to_method_calls';
/**
* @var string
* @var GetAndSetToMethodCall[]
*/
private const GET = 'get';
/**
* @var string[][]
*/
private $typeToMethodCalls = [];
private $getAndSetToMethodCalls = [];
/**
* @var PropertyFetchAnalyzer
@ -75,28 +70,7 @@ CODE_SAMPLE
,
[
self::TYPE_TO_METHOD_CALLS => [
'SomeContainer' => [
'set' => 'addService',
],
],
]
),
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
$container = new SomeContainer;
$someService = $container->someService;
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$container = new SomeContainer;
$someService = $container->getService("someService");
CODE_SAMPLE
,
[
self::TYPE_TO_METHOD_CALLS => [
'SomeContainer' => [
self::GET => 'getService',
],
new GetAndSetToMethodCall('SomeContainer', 'addService', 'getService'),
],
]
),
@ -117,35 +91,39 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
if ($node instanceof Assign) {
if (StaticNodeInstanceOf::isOneOf($node->var, [PropertyFetch::class, StaticPropertyFetch::class])) {
return $this->processMagicSet($node);
if ($node->var instanceof PropertyFetch) {
return $this->processMagicSet($node->expr, $node->var);
}
return null;
}
return $this->processPropertyFetch($node);
}
/**
* @param array<string, GetAndSetToMethodCall[]> $configuration
*/
public function configure(array $configuration): void
{
$this->typeToMethodCalls = $configuration[self::TYPE_TO_METHOD_CALLS] ?? [];
$getAndSetToMethodCalls = $configuration[self::TYPE_TO_METHOD_CALLS] ?? [];
Assert::allIsAOf($getAndSetToMethodCalls, GetAndSetToMethodCall::class);
$this->getAndSetToMethodCalls = $getAndSetToMethodCalls;
}
private function processMagicSet(Assign $assign): ?Node
private function processMagicSet(Expr $expr, PropertyFetch $propertyFetch): ?Node
{
/** @var PropertyFetch $propertyFetchNode */
$propertyFetchNode = $assign->var;
foreach ($this->typeToMethodCalls as $type => $transformation) {
$objectType = new ObjectType($type);
if ($this->shouldSkipPropertyFetch($propertyFetchNode, $objectType)) {
foreach ($this->getAndSetToMethodCalls as $getAndSetToMethodCall) {
$objectType = $getAndSetToMethodCall->getObjectType();
if ($this->shouldSkipPropertyFetch($propertyFetch, $objectType)) {
continue;
}
return $this->createMethodCallNodeFromAssignNode(
$propertyFetchNode,
$assign->expr,
$transformation['set']
$propertyFetch,
$expr,
$getAndSetToMethodCall->getSetMethod()
);
}
@ -154,21 +132,27 @@ CODE_SAMPLE
private function processPropertyFetch(PropertyFetch $propertyFetch): ?MethodCall
{
foreach ($this->typeToMethodCalls as $type => $transformation) {
$objectType = new ObjectType($type);
if ($this->shouldSkipPropertyFetch($propertyFetch, $objectType)) {
$parentNode = $propertyFetch->getAttribute(AttributeKey::PARENT_NODE);
foreach ($this->getAndSetToMethodCalls as $getAndSetToMethodCall) {
if ($this->shouldSkipPropertyFetch($propertyFetch, $getAndSetToMethodCall->getObjectType())) {
continue;
}
// setter, skip
$parentNode = $propertyFetch->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof Assign) {
return $this->createMethodCallNodeFromPropertyFetchNode($propertyFetch, $transformation[self::GET]);
return $this->createMethodCallNodeFromPropertyFetchNode(
$propertyFetch,
$getAndSetToMethodCall->getGetMethod()
);
}
if ($parentNode->var !== $propertyFetch) {
return $this->createMethodCallNodeFromPropertyFetchNode($propertyFetch, $transformation[self::GET]);
return $this->createMethodCallNodeFromPropertyFetchNode(
$propertyFetch,
$getAndSetToMethodCall->getGetMethod()
);
}
continue;
}
return null;
@ -192,10 +176,8 @@ CODE_SAMPLE
Expr $expr,
string $method
): MethodCall {
/** @var Variable $variableNode */
$variableNode = $propertyFetch->var;
return $this->nodeFactory->createMethodCall($variableNode, $method, [$this->getName($propertyFetch), $expr]);
$propertyName = $this->getName($propertyFetch->name);
return $this->nodeFactory->createMethodCall($propertyFetch->var, $method, [$propertyName, $expr]);
}
private function createMethodCallNodeFromPropertyFetchNode(

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\ValueObject;
use PHPStan\Type\ObjectType;
final class GetAndSetToMethodCall
{
/**
* @var class-string
*/
private $classType;
/**
* @var string
*/
private $getMethod;
/**
* @var string
*/
private $setMethod;
/**
* @param class-string $classType
*/
public function __construct(string $classType, string $getMethod, string $setMethod)
{
$this->classType = $classType;
$this->getMethod = $getMethod;
$this->setMethod = $setMethod;
}
public function getGetMethod(): string
{
return $this->getMethod;
}
public function getSetMethod(): string
{
return $this->setMethod;
}
public function getObjectType(): ObjectType
{
return new ObjectType($this->classType);
}
}

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Rector\Core\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
@ -72,19 +73,26 @@ final class PropertyFetchAnalyzer
});
}
public function isPropertyToSelf(PropertyFetch $propertyFetch): bool
/**
* @param PropertyFetch|StaticPropertyFetch $expr
*/
public function isPropertyToSelf(Expr $expr): bool
{
if (! $this->nodeNameResolver->isName($propertyFetch->var, 'this')) {
if ($expr instanceof PropertyFetch && ! $this->nodeNameResolver->isName($expr->var, 'this')) {
return false;
}
$classLike = $propertyFetch->getAttribute(AttributeKey::CLASS_NODE);
if ($expr instanceof StaticPropertyFetch && ! $this->nodeNameResolver->isName($expr->class, 'self')) {
return false;
}
$classLike = $expr->getAttribute(AttributeKey::CLASS_NODE);
if (! $classLike instanceof Class_) {
return false;
}
foreach ($classLike->getProperties() as $property) {
if (! $this->nodeNameResolver->areNamesEqual($property->props[0], $propertyFetch)) {
if (! $this->nodeNameResolver->areNamesEqual($property->props[0], $expr)) {
continue;
}

View File

@ -27,7 +27,6 @@ use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
@ -307,7 +306,7 @@ final class ClassMethodAssignManipulator
return false;
}
if (StaticNodeInstanceOf::isOneOf($node, [Arg::class, ClosureUse::class, Param::class])) {
if ($node instanceof Arg || $node instanceof ClosureUse || $node instanceof Param) {
return $node->byRef;
}

View File

@ -11,7 +11,6 @@ use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\NodeTraverser;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeNameResolver\NodeNameResolver;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
@ -59,7 +58,7 @@ final class ClassMethodPropertyFetchManipulator
return null;
}
if (StaticNodeInstanceOf::isOneOf($node->expr, [MethodCall::class, StaticCall::class])) {
if ($node->expr instanceof MethodCall || $node->expr instanceof StaticCall) {
return null;
}

View File

@ -5,7 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\NodeManipulator;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ErrorType;
@ -48,9 +50,12 @@ final class MagicPropertyFetchAnalyzer
$this->reflectionProvider = $reflectionProvider;
}
public function isMagicOnType(PropertyFetch $propertyFetch, Type $type): bool
/**
* @param PropertyFetch|Node\Expr\StaticPropertyFetch $expr
*/
public function isMagicOnType(Expr $expr, Type $type): bool
{
$varNodeType = $this->nodeTypeResolver->resolve($propertyFetch);
$varNodeType = $this->nodeTypeResolver->resolve($expr);
if ($varNodeType instanceof ErrorType) {
return true;
@ -64,22 +69,30 @@ final class MagicPropertyFetchAnalyzer
return false;
}
$nodeName = $this->nodeNameResolver->getName($propertyFetch);
$nodeName = $this->nodeNameResolver->getName($expr->name);
if ($nodeName === null) {
return false;
}
return ! $this->hasPublicProperty($propertyFetch, $nodeName);
return ! $this->hasPublicProperty($expr, $nodeName);
}
private function hasPublicProperty(PropertyFetch $propertyFetch, string $propertyName): bool
/**
* @param PropertyFetch|StaticPropertyFetch $expr
*/
private function hasPublicProperty(Expr $expr, string $propertyName): bool
{
$scope = $propertyFetch->getAttribute(AttributeKey::SCOPE);
$scope = $expr->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
throw new ShouldNotHappenException();
}
$propertyFetchType = $scope->getType($propertyFetch->var);
if ($expr instanceof PropertyFetch) {
$propertyFetchType = $scope->getType($expr->var);
} else {
$propertyFetchType = $this->nodeTypeResolver->resolve($expr->class);
}
if (! $propertyFetchType instanceof TypeWithClassName) {
return false;
}
@ -95,7 +108,6 @@ final class MagicPropertyFetchAnalyzer
}
$propertyReflection = $classReflection->getProperty($propertyName, $scope);
return $propertyReflection->isPublic();
}
}

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Expr\NullsafeMethodCall;
use PhpParser\Node\Expr\NullsafePropertyFetch;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Identifier;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class NullsafeManipulator
@ -36,7 +35,7 @@ final class NullsafeManipulator
$parentIdentifier = $nextExprIdentifier->getAttribute(AttributeKey::PARENT_NODE);
if (StaticNodeInstanceOf::isOneOf($parentIdentifier, [MethodCall::class, NullsafeMethodCall::class])) {
if ($parentIdentifier instanceof MethodCall || $parentIdentifier instanceof NullsafeMethodCall) {
return new NullsafeMethodCall($expr, $nextExprIdentifier);
}

View File

@ -16,8 +16,8 @@ use PhpParser\Node\Stmt;
use PhpParser\Parser;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Util\StaticNodeInstanceOf;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
use Symplify\SmartFileSystem\SmartFileSystem;
final class InlineCodeParser
{
@ -33,6 +33,18 @@ final class InlineCodeParser
*/
private const CURLY_BRACKET_WRAPPER_REGEX = "#'{(\\\$.*?)}'#";
/**
* @var string
* @see https://regex101.com/r/TBlhoR/1
*/
private const OPEN_PHP_TAG_REGEX = '#^\<\?php\s+#';
/**
* @var string
* @see https://regex101.com/r/TUWwKw/1/
*/
private const ENDING_SEMI_COLON_REGEX = '#;(\s+)?$#';
/**
* @var Parser
*/
@ -48,14 +60,21 @@ final class InlineCodeParser
*/
private $betterStandardPrinter;
/**
* @var SmartFileSystem
*/
private $smartFileSystem;
public function __construct(
BetterStandardPrinter $betterStandardPrinter,
NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator,
Parser $parser
Parser $parser,
SmartFileSystem $smartFileSystem
) {
$this->parser = $parser;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
$this->smartFileSystem = $smartFileSystem;
}
/**
@ -63,12 +82,16 @@ final class InlineCodeParser
*/
public function parse(string $content): array
{
// to cover files too
if (is_file($content)) {
$content = $this->smartFileSystem->readFile($content);
}
// wrap code so php-parser can interpret it
$content = Strings::startsWith($content, '<?php ') ? $content : '<?php ' . $content;
$content = Strings::endsWith($content, ';') ? $content : $content . ';';
$content = Strings::match($content, self::OPEN_PHP_TAG_REGEX) ? $content : '<?php ' . $content;
$content = Strings::match($content, self::ENDING_SEMI_COLON_REGEX) ? $content : $content . ';';
$nodes = (array) $this->parser->parse($content);
return $this->nodeScopeAndMetadataDecorator->decorateNodesFromString($nodes);
}
@ -91,7 +114,7 @@ final class InlineCodeParser
return $this->stringify($expr->left) . $this->stringify($expr->right);
}
if (StaticNodeInstanceOf::isOneOf($expr, [Variable::class, PropertyFetch::class, StaticPropertyFetch::class])) {
if ($expr instanceof Variable || $expr instanceof PropertyFetch || $expr instanceof StaticPropertyFetch) {
return $this->betterStandardPrinter->print($expr);
}