Removing parent classes (#5714)

This commit is contained in:
Tomas Votruba 2021-03-01 02:28:35 +01:00 committed by GitHub
parent da5f4a08c8
commit 47743269e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 232 additions and 218 deletions

View File

@ -48,16 +48,16 @@
"symfony/finder": "^4.4.8|^5.1",
"symfony/http-kernel": "^4.4.8|^5.1",
"symfony/process": "^4.4.8|^5.1",
"symplify/astral": "^9.2.1",
"symplify/autowire-array-parameter": "^9.2.1",
"symplify/console-color-diff": "^9.2.1",
"symplify/package-builder": "^9.2.1",
"symplify/rule-doc-generator": "^9.2.1",
"symplify/set-config-resolver": "^9.2.1",
"symplify/simple-php-doc-parser": "^9.2.1",
"symplify/skipper": "^9.2.1",
"symplify/smart-file-system": "^9.2.1",
"symplify/symfony-php-config": "^9.2.1",
"symplify/astral": "dev-master",
"symplify/autowire-array-parameter": "dev-master",
"symplify/console-color-diff": "dev-master",
"symplify/package-builder": "dev-master",
"symplify/rule-doc-generator": "dev-master",
"symplify/set-config-resolver": "dev-master",
"symplify/simple-php-doc-parser": "dev-master",
"symplify/skipper": "dev-master",
"symplify/smart-file-system": "dev-master",
"symplify/symfony-php-config": "dev-master",
"webmozart/assert": "^1.9"
},
"require-dev": {
@ -71,14 +71,14 @@
"phpunit/phpunit": "^9.5",
"symfony/security-core": "^5.2",
"symfony/security-http": "^5.2",
"symplify/changelog-linker": "^9.2.1",
"symplify/coding-standard": "^9.2.1",
"symplify/changelog-linker": "dev-master",
"symplify/coding-standard": "dev-master",
"symplify/easy-ci": "^9.1.0",
"symplify/easy-coding-standard": "^9.2.1",
"symplify/easy-testing": "^9.2.1",
"symplify/easy-coding-standard": "dev-master",
"symplify/easy-testing": "dev-master",
"symplify/monorepo-builder": "^9.2",
"symplify/phpstan-extensions": "^9.2.1",
"symplify/phpstan-rules": "^9.2.1",
"symplify/phpstan-extensions": "dev-master",
"symplify/phpstan-rules": "dev-master",
"tracy/tracy": "^2.8"
},
"replace": {
@ -328,5 +328,7 @@
},
"config": {
"sort-packages": true
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@ -596,6 +596,12 @@ parameters:
paths:
- packages/node-type-resolver/tests
- '#Content of method "configure\(\)" is duplicated with method "configure\(\)" in "Rector\\Composer\\Rector\\AddPackageToRequireComposerRector" class\. Use unique content or abstract service instead#'
- '#Content of method "isConflicting\(\)" is duplicated with method "isConflicting\(\)" in "Rector\\Naming\\Guard\\PropertyConflictingNameGuard\\MatchPropertyTypeConflictingNameGuard" class\. Use unique content or abstract service instead#'
- '#Content of method "isConflicting\(\)" is duplicated with method "isConflicting\(\)" in "Rector\\Naming\\Guard\\PropertyConflictingNameGuard\\BoolPropertyConflictingNameGuard" class\. Use unique content or abstract service instead#'
- '#Content of method "configure\(\)" is duplicated with method "configure\(\)" in "Rector\\Composer\\Rector\\AddPackageToRequireComposerRector" class\. Use unique content or service instead#'
- '#Content of method "getFunctionLikePhpDocInfo\(\)" is duplicated with method "getFunctionLikePhpDocInfo\(\)" in "Rector\\TypeDeclaration\\TypeInferer\\ParamTypeInferer\\PHPUnitDataProviderParamTypeInferer" class\. Use unique content or service instead#'
- '#PHPDoc tag @return with type PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Function_\|Rector\\Naming\\Matcher\\Closure\|null is not subtype of native type PhpParser\\Node\\FunctionLike\|null#'
-
message: '#Do not use "array_filter" function with complex content, make it more readable with extracted method or single\-line statement#'
paths:
- src/Application/ActiveRectorsProvider.php

View File

@ -106,12 +106,17 @@ CODE_SAMPLE
private function shouldRefactor(Array_ $array): bool
{
// Check that any item in the array is the spread
return array_filter($array->items, function (?ArrayItem $item): bool {
if ($item === null) {
return false;
foreach ($array->items as $item) {
if (! $item instanceof ArrayItem) {
continue;
}
return $item->unpack;
}) !== [];
if ($item->unpack) {
return true;
}
}
return false;
}
private function refactorNode(Array_ $array): Node

View File

@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Naming\Contract\Matcher;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use Rector\Naming\ValueObject\VariableAndCallAssign;
use Rector\Naming\ValueObject\VariableAndCallForeach;
interface MatcherInterface
{
public function getVariable(Node $node): Variable;
public function getVariableName(Node $node): ?string;
/**
* @return VariableAndCallAssign|VariableAndCallForeach
*/
public function match(Node $node);
}

View File

@ -1,95 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Naming\Matcher;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Function_;
use Rector\Naming\Contract\Matcher\MatcherInterface;
use Rector\Naming\ValueObject\VariableAndCallAssign;
use Rector\Naming\ValueObject\VariableAndCallForeach;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
abstract class AbstractMatcher implements MatcherInterface
{
/**
* @var NodeNameResolver
*/
protected $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @param Assign|Foreach_ $node
* @return VariableAndCallAssign|VariableAndCallForeach|null
*/
public function match(Node $node)
{
$call = $this->matchCall($node);
if ($call === null) {
return null;
}
$variableName = $this->getVariableName($node);
if ($variableName === null) {
return null;
}
$functionLike = $this->getFunctionLike($node);
if ($functionLike === null) {
return null;
}
$variable = $this->getVariable($node);
if ($node instanceof Foreach_) {
return new VariableAndCallForeach($variable, $call, $variableName, $functionLike);
}
return new VariableAndCallAssign($variable, $call, $node, $variableName, $functionLike);
}
/**
* @param Assign|Foreach_ $node
* @return FuncCall|StaticCall|MethodCall|null
*/
private function matchCall(Node $node): ?Node
{
if ($node->expr instanceof MethodCall) {
return $node->expr;
}
if ($node->expr instanceof StaticCall) {
return $node->expr;
}
if ($node->expr instanceof FuncCall) {
return $node->expr;
}
return null;
}
/**
* @return ClassMethod|Function_|Closure|null
*/
private function getFunctionLike(Node $node): ?FunctionLike
{
return $node->getAttribute(AttributeKey::CLOSURE_NODE) ??
$node->getAttribute(AttributeKey::METHOD_NODE) ??
$node->getAttribute(AttributeKey::FUNCTION_NODE);
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Rector\Naming\Matcher;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Foreach_;
final class CallMatcher
{
/**
* @param Assign|Foreach_ $node
* @return FuncCall|StaticCall|MethodCall|null
*/
public function matchCall(Node $node): ?Node
{
if ($node->expr instanceof MethodCall) {
return $node->expr;
}
if ($node->expr instanceof StaticCall) {
return $node->expr;
}
if ($node->expr instanceof FuncCall) {
return $node->expr;
}
return null;
}
}

View File

@ -4,31 +4,65 @@ declare(strict_types=1);
namespace Rector\Naming\Matcher;
use PhpParser\Node;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Function_;
use Rector\Naming\ValueObject\VariableAndCallForeach;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class ForeachMatcher extends AbstractMatcher
final class ForeachMatcher
{
/**
* @param Foreach_ $node
* @var NodeNameResolver
*/
public function getVariableName(Node $node): ?string
private $nodeNameResolver;
/**
* @var CallMatcher
*/
private $callMatcher;
public function __construct(NodeNameResolver $nodeNameResolver, CallMatcher $callMatcher)
{
if (! $node->valueVar instanceof Variable) {
$this->nodeNameResolver = $nodeNameResolver;
$this->callMatcher = $callMatcher;
}
public function match(Foreach_ $foreach): ?VariableAndCallForeach
{
$call = $this->callMatcher->matchCall($foreach);
if ($call === null) {
return null;
}
return $this->nodeNameResolver->getName($node->valueVar);
if (! $foreach->valueVar instanceof Variable) {
return null;
}
$functionLike = $this->getFunctionLike($foreach);
if ($functionLike === null) {
return null;
}
$variableName = $this->nodeNameResolver->getName($foreach->valueVar);
if ($variableName === null) {
return null;
}
return new VariableAndCallForeach($foreach->valueVar, $call, $variableName, $functionLike);
}
/**
* @param Foreach_ $node
* @return ClassMethod|Function_|Closure|null
*/
public function getVariable(Node $node): Variable
private function getFunctionLike(Foreach_ $foreach): ?FunctionLike
{
/** @var Variable $variable */
$variable = $node->valueVar;
return $variable;
return $foreach->getAttribute(AttributeKey::CLOSURE_NODE) ??
$foreach->getAttribute(AttributeKey::METHOD_NODE) ??
$foreach->getAttribute(AttributeKey::FUNCTION_NODE);
}
}

View File

@ -4,31 +4,65 @@ declare(strict_types=1);
namespace Rector\Naming\Matcher;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Naming\ValueObject\VariableAndCallAssign;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class VariableAndCallAssignMatcher extends AbstractMatcher
final class VariableAndCallAssignMatcher
{
/**
* @param Assign $node
* @var CallMatcher
*/
public function getVariableName(Node $node): ?string
private $callMatcher;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(CallMatcher $callMatcher, NodeNameResolver $nodeNameResolver)
{
if (! $node->var instanceof Variable) {
$this->callMatcher = $callMatcher;
$this->nodeNameResolver = $nodeNameResolver;
}
public function match(Assign $assign): ?VariableAndCallAssign
{
$call = $this->callMatcher->matchCall($assign);
if ($call === null) {
return null;
}
return $this->nodeNameResolver->getName($node->var);
if (! $assign->var instanceof Variable) {
return null;
}
$variableName = $this->nodeNameResolver->getName($assign->var);
if ($variableName === null) {
return null;
}
$functionLike = $this->getFunctionLike($assign);
if (! $functionLike instanceof FunctionLike) {
return null;
}
return new VariableAndCallAssign($assign->var, $call, $assign, $variableName, $functionLike);
}
/**
* @param Assign $node
* @return ClassMethod|Function_|Closure|null
*/
public function getVariable(Node $node): Variable
private function getFunctionLike(Assign $assign): ?FunctionLike
{
/** @var Variable $variable */
$variable = $node->var;
return $variable;
return $assign->getAttribute(AttributeKey::CLOSURE_NODE) ??
$assign->getAttribute(AttributeKey::METHOD_NODE) ??
$assign->getAttribute(AttributeKey::FUNCTION_NODE);
}
}

View File

@ -5,8 +5,7 @@ declare(strict_types=1);
namespace Rector\Naming\Naming;
use Nette\Utils\Strings;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
@ -314,8 +313,7 @@ final class PropertyNaming
$classMethods = $this->betterNodeFinder->findInstanceOf($classLike, ClassMethod::class);
return array_filter($classMethods, function (ClassMethod $classMethod): bool {
$classMethodName = $this->nodeNameResolver->getName($classMethod);
return Strings::match($classMethodName, self::PREFIXED_CLASS_METHODS_REGEX) !== null;
return $this->isBoolishMethodName($classMethod);
});
}
@ -327,28 +325,10 @@ final class PropertyNaming
array $prefixedClassMethods,
Property $property
): array {
$currentName = $this->nodeNameResolver->getName($property);
$classMethodName = $this->nodeNameResolver->getName($property);
return array_filter($prefixedClassMethods, function (ClassMethod $classMethod) use ($currentName): bool {
if ((array) $classMethod->stmts === []) {
return false;
}
$return = $classMethod->stmts[0];
if (! $return instanceof Return_) {
return false;
}
$node = $return->expr;
if (! $node instanceof Expr) {
return false;
}
if ($node instanceof MethodCall) {
return false;
}
return $this->nodeNameResolver->isName($node, $currentName);
return array_filter($prefixedClassMethods, function (ClassMethod $classMethod) use ($classMethodName): bool {
return $this->doesClassMethodMatchReturnPropertyFetch($classMethod, $classMethodName);
});
}
@ -375,4 +355,27 @@ final class PropertyNaming
return ctype_digit($char);
}
private function isBoolishMethodName(ClassMethod $classMethod): bool
{
$classMethodName = $this->nodeNameResolver->getName($classMethod);
return (bool) Strings::match($classMethodName, self::PREFIXED_CLASS_METHODS_REGEX);
}
private function doesClassMethodMatchReturnPropertyFetch(
ClassMethod $classMethod,
string $currentClassMethodName
): bool {
$possibleReturn = $classMethod->stmts[0] ?? null;
if (! $possibleReturn instanceof Return_) {
return false;
}
$node = $possibleReturn->expr;
if (! $node instanceof PropertyFetch) {
return false;
}
return $this->nodeNameResolver->isName($node->name, $currentClassMethodName);
}
}

View File

@ -111,25 +111,24 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
$variableAndCallAssign = $this->varValueAndCallForeachMatcher->match($node);
if (! $variableAndCallAssign instanceof VariableAndCallForeach) {
$variableAndCallForeach = $this->varValueAndCallForeachMatcher->match($node);
if (! $variableAndCallForeach instanceof VariableAndCallForeach) {
return null;
}
$expectedName = $this->expectedNameResolver->resolveForForeach($variableAndCallAssign->getCall());
$expectedName = $this->expectedNameResolver->resolveForForeach($variableAndCallForeach->getCall());
if ($expectedName === null) {
return null;
}
if ($this->isName($variableAndCallAssign->getVariable(), $expectedName)) {
if ($this->isName($variableAndCallForeach->getVariable(), $expectedName)) {
return null;
}
if ($this->shouldSkip($variableAndCallAssign, $expectedName)) {
if ($this->shouldSkip($variableAndCallForeach, $expectedName)) {
return null;
}
$this->renameVariable($variableAndCallAssign, $expectedName);
$this->renameVariable($variableAndCallForeach, $expectedName);
return $node;
}

View File

@ -2,7 +2,7 @@
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchExprVariableRector\Fixture;
class PropertyFetch
final class SomePropertyFetch
{
public function run()
{
@ -19,7 +19,7 @@ class PropertyFetch
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchExprVariableRector\Fixture;
class PropertyFetch
final class SomePropertyFetch
{
public function run()
{

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Rector\TypeDeclaration\TypeInferer\ParamTypeInferer;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
@ -23,7 +24,6 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\TypeDeclaration\Contract\TypeInferer\ParamTypeInfererInterface;
use PhpParser\Node\Expr\ArrayItem;
final class PHPUnitDataProviderParamTypeInferer implements ParamTypeInfererInterface
{
@ -113,17 +113,17 @@ final class PHPUnitDataProviderParamTypeInferer implements ParamTypeInfererInter
{
$paramOnPositionTypes = [];
if(! $returns[0]->expr instanceof Array_ ) {
if (! $returns[0]->expr instanceof Array_) {
throw new ShouldNotHappenException();
}
foreach ($returns[0]->expr->items as $singleDataProvidedSet) {
if(! $singleDataProvidedSet instanceof ArrayItem || ! $singleDataProvidedSet->value instanceof Array_) {
if (! $singleDataProvidedSet instanceof ArrayItem || ! $singleDataProvidedSet->value instanceof Array_) {
throw new ShouldNotHappenException();
}
foreach($singleDataProvidedSet->value->items as $position => $singleDataProvidedSetItem ) {
if( $position !== $parameterPosition || ! $singleDataProvidedSetItem instanceof ArrayItem ) {
foreach ($singleDataProvidedSet->value->items as $position => $singleDataProvidedSetItem) {
if ($position !== $parameterPosition || ! $singleDataProvidedSetItem instanceof ArrayItem) {
continue;
}

View File

@ -8,7 +8,6 @@ use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Trait_;
@ -99,15 +98,20 @@ final class ClassManipulator
*/
public function getPublicMethodNames(Class_ $class): array
{
$publicMethods = array_filter($class->getMethods(), function (ClassMethod $classMethod): bool {
$publicMethodNames = [];
foreach ($class->getMethods() as $classMethod) {
if ($classMethod->isAbstract()) {
return false;
continue;
}
return $classMethod->isPublic();
});
if ($classMethod->isAbstract()) {
continue;
}
return $this->nodeNameResolver->getNames($publicMethods);
$publicMethodNames[] = $this->nodeNameResolver->getName($classMethod);
}
return $publicMethodNames;
}
/**

View File

@ -185,8 +185,8 @@ final class ClassMethodAssignManipulator
private function filterOutMultiAssigns(array $readOnlyVariableAssigns): array
{
return array_filter($readOnlyVariableAssigns, function (Assign $assign): bool {
$parentNode = $assign->getAttribute(AttributeKey::PARENT_NODE);
return ! $parentNode instanceof Assign;
$parent = $assign->getAttribute(AttributeKey::PARENT_NODE);
return ! $parent instanceof Assign;
});
}

View File

@ -123,10 +123,7 @@ final class VariableManipulator
public function filterOutChangedVariables(array $assignsOfArrayToVariable, ClassMethod $classMethod): array
{
return array_filter($assignsOfArrayToVariable, function (Assign $assign) use ($classMethod): bool {
/** @var Variable $variable */
$variable = $assign->var;
return $this->isReadOnlyVariable($classMethod, $variable, $assign);
return $this->isReadOnlyVariable($classMethod, $assign);
});
}
@ -145,8 +142,13 @@ final class VariableManipulator
* Inspiration
* @see \Rector\Core\NodeManipulator\PropertyManipulator::isReadOnlyProperty()
*/
private function isReadOnlyVariable(ClassMethod $classMethod, Variable $variable, Assign $assign): bool
private function isReadOnlyVariable(ClassMethod $classMethod, Assign $assign): bool
{
if (! $assign->var instanceof Variable) {
return false;
}
$variable = $assign->var;
$variableUsages = $this->collectVariableUsages($classMethod, $variable, $assign);
foreach ($variableUsages as $variableUsage) {

View File

@ -12,8 +12,6 @@ services:
- PHPStan\Type\StaticType
- Rector\BetterPhpDocParser\PhpDocNodeFactory\AbstractPhpDocNodeFactory
- PHPStan\PhpDocParser\Parser\PhpDocParser
# resolve later
- Rector\Naming\Matcher\AbstractMatcher
# value objects
- Rector\Defluent\ValueObject\AbstractRootExpr
- Symplify\SetConfigResolver\Provider\AbstractSetProvider
@ -54,6 +52,14 @@ services:
# forbidddenTypes:
# - PhpParser\Node
-
class: Symplify\PHPStanRules\Rules\ForbiddenComplexFuncCallRule
tags: [phpstan.rules.rule]
arguments:
forbiddenComplexFunctions:
- array_filter
maximumStmtCount: 3
-
class: Symplify\PHPStanRules\Rules\IfNewTypeThenImplementInterfaceRule
tags: [phpstan.rules.rule]