mirror of
https://github.com/rectorphp/rector.git
synced 2025-03-14 04:19:44 +01:00
[Naming] Rename foreach value variable to match method return type (#4130)
Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
parent
7a498e328e
commit
f69ea0e023
@ -8,6 +8,7 @@ use Rector\Naming\Rector\ClassMethod\MakeGetterClassMethodNameStartWithGetRector
|
||||
use Rector\Naming\Rector\ClassMethod\MakeIsserClassMethodNameStartWithIsRector;
|
||||
use Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector;
|
||||
use Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector;
|
||||
use Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
@ -18,4 +19,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services->set(RenameVariableToMatchMethodCallReturnTypeRector::class);
|
||||
$services->set(MakeGetterClassMethodNameStartWithGetRector::class);
|
||||
$services->set(MakeIsserClassMethodNameStartWithIsRector::class);
|
||||
$services->set(RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class);
|
||||
};
|
||||
|
@ -232,8 +232,8 @@ final class PhpDocInfoPrinter
|
||||
): string {
|
||||
// skip removed nodes
|
||||
$positionJumpSet = [];
|
||||
foreach ($this->getRemovedNodesPositions() as $removedTokensPosition) {
|
||||
$positionJumpSet[$removedTokensPosition->getStart()] = $removedTokensPosition->getEnd();
|
||||
foreach ($this->getRemovedNodesPositions() as $startAndEnd) {
|
||||
$positionJumpSet[$startAndEnd->getStart()] = $startAndEnd->getEnd();
|
||||
}
|
||||
|
||||
// include also space before, in case of inlined docs
|
||||
|
@ -50,8 +50,8 @@ final class DependencyResolver
|
||||
}
|
||||
|
||||
$dependencies = [];
|
||||
foreach ($this->phpStanDependencyResolver->resolveDependencies($node, $scope) as $dependencyReflection) {
|
||||
$dependencyFile = $dependencyReflection->getFileName();
|
||||
foreach ($this->phpStanDependencyResolver->resolveDependencies($node, $scope) as $nodeDependency) {
|
||||
$dependencyFile = $nodeDependency->getFileName();
|
||||
if (! $dependencyFile) {
|
||||
continue;
|
||||
}
|
||||
|
@ -53,13 +53,13 @@ final class CheckstyleOutputFormatter implements OutputFormatterInterface
|
||||
$message = sprintf('<file name="%s">', $this->escape($fileDiff->getRelativeFilePath()));
|
||||
$this->symfonyStyle->writeln($message);
|
||||
|
||||
foreach ($fileDiff->getRectorChanges() as $rectorChange) {
|
||||
$message = $rectorChange->getRectorDefinitionsDescription() . ' (Reported by: ' . $rectorChange->getRectorClass() . ')';
|
||||
foreach ($fileDiff->getRectorChanges() as $rectorWithFileAndLineChange) {
|
||||
$message = $rectorWithFileAndLineChange->getRectorDefinitionsDescription() . ' (Reported by: ' . $rectorWithFileAndLineChange->getRectorClass() . ')';
|
||||
$message = $this->escape($message);
|
||||
|
||||
$error = sprintf(
|
||||
' <error line="%d" column="1" severity="error" message="%s" />',
|
||||
$this->escape((string) $rectorChange->getLine()),
|
||||
$this->escape((string) $rectorWithFileAndLineChange->getLine()),
|
||||
$message
|
||||
);
|
||||
$this->symfonyStyle->writeln($error);
|
||||
@ -73,8 +73,8 @@ final class CheckstyleOutputFormatter implements OutputFormatterInterface
|
||||
if ($errorAndDiffCollector->getErrors() !== []) {
|
||||
$this->symfonyStyle->writeln('<file>');
|
||||
|
||||
foreach ($errorAndDiffCollector->getErrors() as $error) {
|
||||
$escapedMessage = $this->escape($error->getMessage());
|
||||
foreach ($errorAndDiffCollector->getErrors() as $rectorError) {
|
||||
$escapedMessage = $this->escape($rectorError->getMessage());
|
||||
$message = sprintf(' <error severity="error" message="%s" />', $escapedMessage);
|
||||
|
||||
$this->symfonyStyle->writeln($message);
|
||||
|
@ -247,8 +247,8 @@ final class NodeTypeResolver
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($nodeType->getTypes() as $subtype) {
|
||||
if ($subtype instanceof ObjectType) {
|
||||
foreach ($nodeType->getTypes() as $type) {
|
||||
if ($type instanceof ObjectType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -175,8 +175,8 @@ PHP
|
||||
|
||||
$node = $methodCall;
|
||||
|
||||
foreach ($arrayItemsAndFluentClass->getFluentCalls() as $method => $arg) {
|
||||
$args = $this->createArgs([$arg]);
|
||||
foreach ($arrayItemsAndFluentClass->getFluentCalls() as $method => $expr) {
|
||||
$args = $this->createArgs([$expr]);
|
||||
$node = $this->createMethodCall($node, $method, $args);
|
||||
}
|
||||
|
||||
|
@ -262,9 +262,9 @@ PHP
|
||||
ClassMethod $classMethod,
|
||||
ReflectionMethod $reflectionMethod
|
||||
): bool {
|
||||
foreach ($reflectionMethod->getParameters() as $key => $parameter) {
|
||||
foreach ($reflectionMethod->getParameters() as $key => $reflectionParameter) {
|
||||
if (! isset($classMethod->params[$key])) {
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
if ($reflectionParameter->isDefaultValueAvailable()) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
@ -272,7 +272,7 @@ PHP
|
||||
|
||||
$methodParam = $classMethod->params[$key];
|
||||
|
||||
if ($this->areDefaultValuesDifferent($parameter, $methodParam)) {
|
||||
if ($this->areDefaultValuesDifferent($reflectionParameter, $methodParam)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -217,17 +217,17 @@ PHP
|
||||
private function removeSetAndGetMethods(Class_ $class, array $removedPropertyNames): void
|
||||
{
|
||||
foreach ($removedPropertyNames as $removedPropertyName) {
|
||||
foreach ($class->getMethods() as $method) {
|
||||
if ($this->isName($method, 'set' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($method);
|
||||
foreach ($class->getMethods() as $classMethod) {
|
||||
if ($this->isName($classMethod, 'set' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($classMethod);
|
||||
}
|
||||
|
||||
if ($this->isName($method, 'get' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($method);
|
||||
if ($this->isName($classMethod, 'get' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($classMethod);
|
||||
}
|
||||
|
||||
if ($this->isName($method, 'setTranslatableLocale')) {
|
||||
$this->removeNode($method);
|
||||
if ($this->isName($classMethod, 'setTranslatableLocale')) {
|
||||
$this->removeNode($classMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -198,13 +198,13 @@ PHP
|
||||
private function removeClassMethodsForProperties(Class_ $class, array $removedPropertyNames): void
|
||||
{
|
||||
foreach ($removedPropertyNames as $removedPropertyName) {
|
||||
foreach ($class->getMethods() as $method) {
|
||||
if ($this->isName($method, 'get' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($method);
|
||||
foreach ($class->getMethods() as $classMethod) {
|
||||
if ($this->isName($classMethod, 'get' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($classMethod);
|
||||
}
|
||||
|
||||
if ($this->isName($method, 'set' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($method);
|
||||
if ($this->isName($classMethod, 'set' . ucfirst($removedPropertyName))) {
|
||||
$this->removeNode($classMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,9 +93,9 @@ final class CallTypeAnalyzer
|
||||
|
||||
$parameterTypes = [];
|
||||
|
||||
/** @var ParameterReflection $parameter */
|
||||
foreach ($functionVariant->getParameters() as $parameter) {
|
||||
$parameterTypes[] = $parameter->getType();
|
||||
/** @var ParameterReflection $parameterReflection */
|
||||
foreach ($functionVariant->getParameters() as $parameterReflection) {
|
||||
$parameterTypes[] = $parameterReflection->getType();
|
||||
}
|
||||
|
||||
return $parameterTypes;
|
||||
|
@ -13,6 +13,7 @@ use Rector\Core\RectorDefinition\ConfiguredCodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Generic\ValueObject\ParentDependency;
|
||||
use Rector\Naming\Naming\PropertyNaming;
|
||||
use Rector\Naming\ValueObject\ExpectedName;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
@ -100,9 +101,9 @@ CODE_SAMPLE
|
||||
}
|
||||
|
||||
$propertyType = new ObjectType($parentDependency->getDependencyType());
|
||||
/** @var string $propertyName */
|
||||
/** @var ExpectedName $propertyName */
|
||||
$propertyName = $this->propertyNaming->getExpectedNameFromType($propertyType);
|
||||
$this->addConstructorDependencyToClass($node, $propertyType, $propertyName);
|
||||
$this->addConstructorDependencyToClass($node, $propertyType, $propertyName->getName());
|
||||
}
|
||||
|
||||
return $node;
|
||||
|
@ -120,25 +120,25 @@ PHP
|
||||
Class_ $class,
|
||||
PropertyAndClassMethodName $propertyAndClassMethodName
|
||||
): Class_ {
|
||||
foreach ($class->getMethods() as $method) {
|
||||
if ($this->isName($method, $propertyAndClassMethodName->getClassMethodName())) {
|
||||
$this->removeNodeFromStatements($class, $method);
|
||||
foreach ($class->getMethods() as $classMethod) {
|
||||
if ($this->isName($classMethod, $propertyAndClassMethodName->getClassMethodName())) {
|
||||
$this->removeNodeFromStatements($class, $classMethod);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->isNames($method, [MethodName::CONSTRUCT, '__clone', '__wakeup'])) {
|
||||
if (! $this->isNames($classMethod, [MethodName::CONSTRUCT, '__clone', '__wakeup'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($method->isPublic()) {
|
||||
if ($classMethod->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// remove non-public empty
|
||||
if ($method->stmts === []) {
|
||||
$this->removeNodeFromStatements($class, $method);
|
||||
if ($classMethod->stmts === []) {
|
||||
$this->removeNodeFromStatements($class, $classMethod);
|
||||
} else {
|
||||
$this->makePublic($method);
|
||||
$this->makePublic($classMethod);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,12 +148,12 @@ final class FluentChainMethodCallRootExtractor
|
||||
}
|
||||
|
||||
$fullyQualifiedObjectType = new FullyQualifiedObjectType($className);
|
||||
$variableName = $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType);
|
||||
if ($variableName === null) {
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType);
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$variable = new Variable($variableName);
|
||||
$variable = new Variable($expectedName->getName());
|
||||
return new AssignAndRootExpr($methodCall->var, $methodCall->var, $variable);
|
||||
}
|
||||
|
||||
|
@ -138,8 +138,8 @@ PHP
|
||||
}
|
||||
|
||||
if ($st instanceof UnionType) {
|
||||
foreach ($st->getTypes() as $candidate) {
|
||||
if ($candidate->equals($resourceType)) {
|
||||
foreach ($st->getTypes() as $type) {
|
||||
if ($type->equals($resourceType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
@ -20,6 +21,7 @@ use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Naming\Naming\ConflictingNameResolver;
|
||||
use Rector\Naming\Naming\OverridenExistingNamesResolver;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper;
|
||||
@ -54,18 +56,25 @@ final class BreakingVariableRenameGuard
|
||||
*/
|
||||
private $typeUnwrapper;
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
public function __construct(
|
||||
BetterNodeFinder $betterNodeFinder,
|
||||
ConflictingNameResolver $conflictingNameResolver,
|
||||
NodeTypeResolver $nodeTypeResolver,
|
||||
OverridenExistingNamesResolver $overridenExistingNamesResolver,
|
||||
TypeUnwrapper $typeUnwrapper
|
||||
TypeUnwrapper $typeUnwrapper,
|
||||
NodeNameResolver $nodeNameResolver
|
||||
) {
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->conflictingNameResolver = $conflictingNameResolver;
|
||||
$this->overridenExistingNamesResolver = $overridenExistingNamesResolver;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
$this->typeUnwrapper = $typeUnwrapper;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,6 +111,10 @@ final class BreakingVariableRenameGuard
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isUsedInForeachKeyValueVar($variable, $currentName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->isUsedInIfAndOtherBranches($variable, $currentName);
|
||||
}
|
||||
|
||||
@ -179,6 +192,34 @@ final class BreakingVariableRenameGuard
|
||||
return $this->betterNodeFinder->hasVariableOfName((array) $functionLike->uses, $expectedName);
|
||||
}
|
||||
|
||||
private function isUsedInForeachKeyValueVar(Variable $variable, string $currentName): bool
|
||||
{
|
||||
$previousForeach = $this->betterNodeFinder->findFirstPreviousOfTypes($variable, [Foreach_::class]);
|
||||
if ($previousForeach instanceof Foreach_) {
|
||||
if ($previousForeach->keyVar === $variable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($previousForeach->valueVar === $variable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->nodeNameResolver->isName($previousForeach->valueVar, $currentName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($previousForeach->keyVar === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->nodeNameResolver->isName($previousForeach->keyVar, $currentName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isUsedInIfAndOtherBranches(Variable $variable, string $currentVariableName): bool
|
||||
{
|
||||
// is in if branches?
|
||||
|
97
rules/naming/src/Matcher/AbstractMatcher.php
Normal file
97
rules/naming/src/Matcher/AbstractMatcher.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?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\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);
|
||||
}
|
||||
|
||||
if ($node instanceof Assign) {
|
||||
return new VariableAndCallAssign($variable, $call, $node, $variableName, $functionLike);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FuncCall|StaticCall|MethodCall|null
|
||||
*/
|
||||
protected 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
|
||||
*/
|
||||
protected function getFunctionLike(Node $node): ?FunctionLike
|
||||
{
|
||||
return $node->getAttribute(AttributeKey::CLOSURE_NODE) ??
|
||||
$node->getAttribute(AttributeKey::METHOD_NODE) ??
|
||||
$node->getAttribute(AttributeKey::FUNCTION_NODE);
|
||||
}
|
||||
}
|
34
rules/naming/src/Matcher/ForeachMatcher.php
Normal file
34
rules/naming/src/Matcher/ForeachMatcher.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Matcher;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
|
||||
final class ForeachMatcher extends AbstractMatcher
|
||||
{
|
||||
/**
|
||||
* @param Foreach_ $node
|
||||
*/
|
||||
public function getVariableName(Node $node): ?string
|
||||
{
|
||||
if (! $node->valueVar instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->nodeNameResolver->getName($node->valueVar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Foreach_ $node
|
||||
*/
|
||||
public function getVariable(Node $node): Variable
|
||||
{
|
||||
/** @var Variable $variable */
|
||||
$variable = $node->valueVar;
|
||||
return $variable;
|
||||
}
|
||||
}
|
22
rules/naming/src/Matcher/MatcherInterface.php
Normal file
22
rules/naming/src/Matcher/MatcherInterface.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\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);
|
||||
}
|
@ -6,81 +6,29 @@ 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\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
|
||||
final class VariableAndCallAssignMatcher extends AbstractMatcher
|
||||
{
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
* @param Assign $node
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
public function __construct(NodeNameResolver $nodeNameResolver)
|
||||
public function getVariableName(Node $node): ?string
|
||||
{
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
}
|
||||
|
||||
public function match(Assign $assign): ?VariableAndCallAssign
|
||||
{
|
||||
$call = $this->matchCall($assign);
|
||||
if ($call === null) {
|
||||
if (! $node->var instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $assign->var instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$variableName = $this->nodeNameResolver->getName($assign->var);
|
||||
if ($variableName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$functionLike = $this->getFunctionLike($assign);
|
||||
if ($functionLike === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VariableAndCallAssign($assign->var, $call, $assign, $variableName, $functionLike);
|
||||
return $this->nodeNameResolver->getName($node->var);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FuncCall|StaticCall|MethodCall|null
|
||||
* @param Assign $node
|
||||
*/
|
||||
private function matchCall(Assign $assign): ?Node
|
||||
public function getVariable(Node $node): Variable
|
||||
{
|
||||
if ($assign->expr instanceof MethodCall) {
|
||||
return $assign->expr;
|
||||
}
|
||||
|
||||
if ($assign->expr instanceof StaticCall) {
|
||||
return $assign->expr;
|
||||
}
|
||||
|
||||
if ($assign->expr instanceof FuncCall) {
|
||||
return $assign->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);
|
||||
/** @var Variable $variable */
|
||||
$variable = $node->var;
|
||||
return $variable;
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,12 @@ use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
@ -106,7 +109,12 @@ final class ExpectedNameResolver
|
||||
}
|
||||
|
||||
$staticType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type);
|
||||
return $this->propertyNaming->getExpectedNameFromType($staticType);
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($staticType);
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName->getName();
|
||||
}
|
||||
|
||||
public function resolveForProperty(Property $property): ?string
|
||||
@ -117,7 +125,12 @@ final class ExpectedNameResolver
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->propertyNaming->getExpectedNameFromType($phpDocInfo->getVarType());
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($phpDocInfo->getVarType());
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName->getName();
|
||||
}
|
||||
|
||||
public function resolveForAssignNonNew(Assign $assign): ?string
|
||||
@ -159,7 +172,12 @@ final class ExpectedNameResolver
|
||||
|
||||
$fullyQualifiedObjectType = new FullyQualifiedObjectType($className);
|
||||
|
||||
return $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType);
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType);
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,8 +205,9 @@ final class ExpectedNameResolver
|
||||
}
|
||||
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($returnedType);
|
||||
|
||||
if ($expectedName !== null) {
|
||||
return $expectedName;
|
||||
return $expectedName->getName();
|
||||
}
|
||||
|
||||
// call with args can return different value, so skip there if not sure about the type
|
||||
@ -196,13 +215,57 @@ final class ExpectedNameResolver
|
||||
return null;
|
||||
}
|
||||
|
||||
// @see https://regex101.com/r/hnU5pm/2/
|
||||
$matches = Strings::match($name, '#^get([A-Z].+)#');
|
||||
if ($matches === null) {
|
||||
$expectedNameFromMethodName = $this->propertyNaming->getExpectedNameFromMethodName($name);
|
||||
if ($expectedNameFromMethodName !== null) {
|
||||
return $expectedNameFromMethodName->getName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall|StaticCall|FuncCall $expr
|
||||
*/
|
||||
public function resolveForForeach(Expr $expr): ?string
|
||||
{
|
||||
if ($this->isDynamicNameCall($expr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return lcfirst($matches[1]);
|
||||
$name = $this->nodeNameResolver->getName($expr->name);
|
||||
if ($name === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$returnedType = $this->nodeTypeResolver->getStaticType($expr);
|
||||
|
||||
if ($returnedType->isIterable()->no()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($returnedType instanceof ArrayType) {
|
||||
$returnedType = $this->resolveReturnTypeFromArrayType($expr, $returnedType);
|
||||
if ($returnedType === null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$expectedNameFromType = $this->propertyNaming->getExpectedNameFromType($returnedType);
|
||||
|
||||
if ($expectedNameFromType !== null) {
|
||||
return $expectedNameFromType->getSingularized();
|
||||
}
|
||||
|
||||
$expectedNameFromMethodName = $this->propertyNaming->getExpectedNameFromMethodName($name);
|
||||
if ($expectedNameFromMethodName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($expectedNameFromMethodName->isSingular()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedNameFromMethodName->getSingularized();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,4 +293,17 @@ final class ExpectedNameResolver
|
||||
|
||||
return $expr->name instanceof FuncCall;
|
||||
}
|
||||
|
||||
private function resolveReturnTypeFromArrayType(Expr $expr, ArrayType $arrayType): ?Type
|
||||
{
|
||||
if (! $expr->getAttribute(AttributeKey::PARENT_NODE) instanceof Foreach_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $arrayType->getItemType() instanceof ObjectType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $arrayType->getItemType();
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Naming;
|
||||
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Nette\Utils\Strings;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StaticType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\Naming\ValueObject\ExpectedName;
|
||||
use Rector\NetteKdyby\Naming\VariableNaming;
|
||||
use Rector\PHPStan\Type\SelfObjectType;
|
||||
use Rector\PHPStan\Type\ShortenedObjectType;
|
||||
@ -37,12 +39,31 @@ final class PropertyNaming
|
||||
*/
|
||||
private $typeUnwrapper;
|
||||
|
||||
public function __construct(TypeUnwrapper $typeUnwrapper)
|
||||
/**
|
||||
* @var Inflector
|
||||
*/
|
||||
private $inflector;
|
||||
|
||||
public function __construct(TypeUnwrapper $typeUnwrapper, Inflector $inflector)
|
||||
{
|
||||
$this->typeUnwrapper = $typeUnwrapper;
|
||||
$this->inflector = $inflector;
|
||||
}
|
||||
|
||||
public function getExpectedNameFromType(Type $type): ?string
|
||||
public function getExpectedNameFromMethodName(string $methodName): ?ExpectedName
|
||||
{
|
||||
// @see https://regex101.com/r/hnU5pm/2/
|
||||
$matches = Strings::match($methodName, '#^get([A-Z].+)#');
|
||||
if ($matches === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$originalName = lcfirst($matches[1]);
|
||||
|
||||
return new ExpectedName($originalName, $this->inflector->singularize($originalName));
|
||||
}
|
||||
|
||||
public function getExpectedNameFromType(Type $type): ?ExpectedName
|
||||
{
|
||||
if ($type instanceof UnionType) {
|
||||
$type = $this->typeUnwrapper->unwrapNullableType($type);
|
||||
@ -81,7 +102,8 @@ final class PropertyNaming
|
||||
$shortClassName = $this->normalizeUpperCase($shortClassName);
|
||||
|
||||
// prolong too short generic names with one namespace up
|
||||
return $this->prolongIfTooShort($shortClassName, $className);
|
||||
$originalName = $this->prolongIfTooShort($shortClassName, $className);
|
||||
return new ExpectedName($originalName, $this->inflector->singularize($originalName));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,6 +146,7 @@ PHP
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var VariableAndCallAssign|null $variableAndCallAssign */
|
||||
$variableAndCallAssign = $this->variableAndCallAssignMatcher->match($node);
|
||||
if ($variableAndCallAssign === null) {
|
||||
return null;
|
||||
@ -189,6 +190,7 @@ PHP
|
||||
|
||||
private function renameVariable(VariableAndCallAssign $variableAndCallAssign, string $expectedName): void
|
||||
{
|
||||
// TODO: Remove in next PR, implemented in VariableRenamer::renameVariableIfMatchesName()
|
||||
$this->varTagValueNodeRenamer->renameAssignVarTagVariableName(
|
||||
$variableAndCallAssign->getAssign(),
|
||||
$variableAndCallAssign->getVariableName(),
|
||||
|
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Rector\Foreach_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Naming\Guard\BreakingVariableRenameGuard;
|
||||
use Rector\Naming\Matcher\ForeachMatcher;
|
||||
use Rector\Naming\Naming\ExpectedNameResolver;
|
||||
use Rector\Naming\NamingConvention\NamingConventionAnalyzer;
|
||||
use Rector\Naming\ValueObject\VariableAndCallForeach;
|
||||
use Rector\Naming\VariableRenamer;
|
||||
|
||||
/**
|
||||
* @see \Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\RenameForeachValueVariableToMatchMethodCallReturnTypeRectorTest
|
||||
*/
|
||||
final class RenameForeachValueVariableToMatchMethodCallReturnTypeRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ExpectedNameResolver
|
||||
*/
|
||||
private $expectedNameResolver;
|
||||
|
||||
/**
|
||||
* @var VariableRenamer
|
||||
*/
|
||||
private $variableRenamer;
|
||||
|
||||
/**
|
||||
* @var ForeachMatcher
|
||||
*/
|
||||
private $varValueAndCallForeachMatcher;
|
||||
|
||||
/**
|
||||
* @var BreakingVariableRenameGuard
|
||||
*/
|
||||
private $breakingVariableRenameGuard;
|
||||
|
||||
/**
|
||||
* @var NamingConventionAnalyzer
|
||||
*/
|
||||
private $namingConventionAnalyzer;
|
||||
|
||||
public function __construct(
|
||||
BreakingVariableRenameGuard $breakingVariableRenameGuard,
|
||||
ExpectedNameResolver $expectedNameResolver,
|
||||
NamingConventionAnalyzer $namingConventionAnalyzer,
|
||||
VariableRenamer $variableRenamer,
|
||||
ForeachMatcher $foreachMatcher
|
||||
) {
|
||||
$this->expectedNameResolver = $expectedNameResolver;
|
||||
$this->variableRenamer = $variableRenamer;
|
||||
$this->breakingVariableRenameGuard = $breakingVariableRenameGuard;
|
||||
$this->namingConventionAnalyzer = $namingConventionAnalyzer;
|
||||
$this->varValueAndCallForeachMatcher = $foreachMatcher;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Renames value variable name in foreach loop to match method type', [
|
||||
new CodeSample(
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = [];
|
||||
foreach ($object->getMethods() as $property) {
|
||||
$array[] = $property;
|
||||
}
|
||||
}
|
||||
}
|
||||
PHP
|
||||
|
||||
,
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = [];
|
||||
foreach ($object->getMethods() as $method) {
|
||||
$array[] = $method;
|
||||
}
|
||||
}
|
||||
}
|
||||
PHP
|
||||
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Foreach_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Foreach_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var VariableAndCallForeach|null $variableAndCallAssign */
|
||||
$variableAndCallAssign = $this->varValueAndCallForeachMatcher->match($node);
|
||||
|
||||
if ($variableAndCallAssign === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$expectedName = $this->expectedNameResolver->resolveForForeach($variableAndCallAssign->getCall());
|
||||
if ($expectedName === null || $this->isName($variableAndCallAssign->getVariable(), $expectedName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->shouldSkip($variableAndCallAssign, $expectedName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->renameVariable($variableAndCallAssign, $expectedName);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function shouldSkip(VariableAndCallForeach $variableAndCallForeach, string $expectedName): bool
|
||||
{
|
||||
if ($this->namingConventionAnalyzer->isCallMatchingVariableName(
|
||||
$variableAndCallForeach->getCall(),
|
||||
$variableAndCallForeach->getVariableName(),
|
||||
$expectedName
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->breakingVariableRenameGuard->shouldSkipVariable(
|
||||
$variableAndCallForeach->getVariableName(),
|
||||
$expectedName,
|
||||
$variableAndCallForeach->getFunctionLike(),
|
||||
$variableAndCallForeach->getVariable()
|
||||
);
|
||||
}
|
||||
|
||||
private function renameVariable(VariableAndCallForeach $variableAndCallForeach, string $expectedName): void
|
||||
{
|
||||
$this->variableRenamer->renameVariableInFunctionLike(
|
||||
$variableAndCallForeach->getFunctionLike(),
|
||||
null,
|
||||
$variableAndCallForeach->getVariableName(),
|
||||
$expectedName
|
||||
);
|
||||
}
|
||||
}
|
39
rules/naming/src/ValueObject/ExpectedName.php
Normal file
39
rules/naming/src/ValueObject/ExpectedName.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ValueObject;
|
||||
|
||||
final class ExpectedName
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $singularized;
|
||||
|
||||
public function __construct(string $name, string $singularized)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->singularized = $singularized;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getSingularized(): string
|
||||
{
|
||||
return $this->singularized;
|
||||
}
|
||||
|
||||
public function isSingular(): bool
|
||||
{
|
||||
return $this->name === $this->singularized;
|
||||
}
|
||||
}
|
76
rules/naming/src/ValueObject/VariableAndCallForeach.php
Normal file
76
rules/naming/src/ValueObject/VariableAndCallForeach.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ValueObject;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
|
||||
final class VariableAndCallForeach
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $variableName;
|
||||
|
||||
/**
|
||||
* @var Variable
|
||||
*/
|
||||
private $variable;
|
||||
|
||||
/**
|
||||
* @var FuncCall|MethodCall|StaticCall
|
||||
*/
|
||||
private $call;
|
||||
|
||||
/**
|
||||
* @var ClassMethod|Function_|Closure
|
||||
*/
|
||||
private $functionLike;
|
||||
|
||||
/**
|
||||
* @param FuncCall|StaticCall|MethodCall $expr
|
||||
* @param ClassMethod|Function_|Closure $functionLike
|
||||
*/
|
||||
public function __construct(Variable $variable, Expr $expr, string $variableName, FunctionLike $functionLike)
|
||||
{
|
||||
$this->variable = $variable;
|
||||
$this->call = $expr;
|
||||
$this->variableName = $variableName;
|
||||
$this->functionLike = $functionLike;
|
||||
}
|
||||
|
||||
public function getVariable(): Variable
|
||||
{
|
||||
return $this->variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FuncCall|StaticCall|MethodCall
|
||||
*/
|
||||
public function getCall(): Expr
|
||||
{
|
||||
return $this->call;
|
||||
}
|
||||
|
||||
public function getVariableName(): string
|
||||
{
|
||||
return $this->variableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMethod|Function_|Closure
|
||||
*/
|
||||
public function getFunctionLike(): FunctionLike
|
||||
{
|
||||
return $this->functionLike;
|
||||
}
|
||||
}
|
@ -77,6 +77,8 @@ final class VariableRenamer
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Remove in next PR (with above param check?),
|
||||
// TODO: Should be implemented in BreakingVariableRenameGuard::shouldSkipParam()
|
||||
if ($this->isParamInParentFunction($node)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Source\Method;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = [];
|
||||
foreach ($this->getMethods() as $property) {
|
||||
$array[] = $property;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Method[]
|
||||
*/
|
||||
public function getMethods(): array
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Source\Method;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = [];
|
||||
foreach ($this->getMethods() as $method) {
|
||||
$array[] = $method;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Method[]
|
||||
*/
|
||||
public function getMethods(): array
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
|
||||
class ForeachPreferParentStmtVariableName
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$searchInNodes = [];
|
||||
foreach ($this->getUsedTraits() as $trait) {
|
||||
$trait = $this->findTrait($trait);
|
||||
if ($trait === null) {
|
||||
continue;
|
||||
}
|
||||
$searchInNodes[] = $trait;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name[]
|
||||
*/
|
||||
public function getUsedTraits(): array
|
||||
{
|
||||
}
|
||||
|
||||
public function findTrait(string $name): Trait_
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
|
||||
class ForeachPreferParentStmtVariableName
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$searchInNodes = [];
|
||||
foreach ($this->getUsedTraits() as $name) {
|
||||
$name = $this->findTrait($name);
|
||||
if ($name === null) {
|
||||
continue;
|
||||
}
|
||||
$searchInNodes[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name[]
|
||||
*/
|
||||
public function getUsedTraits(): array
|
||||
{
|
||||
}
|
||||
|
||||
public function findTrait(string $name): Trait_
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Source\NodeDependencies;
|
||||
|
||||
class IterableTypeWithSingularizationClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = [];
|
||||
foreach ($this->resolveDependencies() as $method) {
|
||||
$array[] = $method;
|
||||
}
|
||||
}
|
||||
|
||||
public function resolveDependencies(): NodeDependencies
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Source\NodeDependencies;
|
||||
|
||||
class IterableTypeWithSingularizationClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = [];
|
||||
foreach ($this->resolveDependencies() as $nodeDependency) {
|
||||
$array[] = $nodeDependency;
|
||||
}
|
||||
}
|
||||
|
||||
public function resolveDependencies(): NodeDependencies
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
class PluralExcludedGetNamesClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$words = [];
|
||||
foreach ($this->getPluralNames() as $word) {
|
||||
$words[] = $word;
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartFileInfo[]
|
||||
*/
|
||||
public function getPluralNames(): array
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
class PluralExcludedGetNamesClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$words = [];
|
||||
foreach ($this->getPluralNames() as $pluralName) {
|
||||
$words[] = $pluralName;
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartFileInfo[]
|
||||
*/
|
||||
public function getPluralNames(): array
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Fixture;
|
||||
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
class SkipSingularAfterGetNamesClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$words = [];
|
||||
foreach ($this->getSingularName() as $word) {
|
||||
$words[] = $word;
|
||||
}
|
||||
|
||||
return $words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartFileInfo[]
|
||||
*/
|
||||
public function getSingularName(): array
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class RenameForeachValueVariableToMatchMethodCallReturnTypeRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Source;
|
||||
|
||||
final class Method
|
||||
{
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Tests\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector\Source;
|
||||
|
||||
use IteratorAggregate;
|
||||
|
||||
/**
|
||||
* @implements \IteratorAggregate<int, ReflectionWithFilename>
|
||||
*/
|
||||
class NodeDependencies implements IteratorAggregate
|
||||
{
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
// TODO: Implement getIterator() method.
|
||||
}
|
||||
}
|
@ -30,14 +30,14 @@ final class LetManipulator
|
||||
|
||||
public function isLetNeededInClass(Class_ $class): bool
|
||||
{
|
||||
foreach ($class->getMethods() as $method) {
|
||||
foreach ($class->getMethods() as $classMethod) {
|
||||
// new test
|
||||
if ($this->nodeNameResolver->isName($method, 'test*')) {
|
||||
if ($this->nodeNameResolver->isName($classMethod, 'test*')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasBeConstructedThrough = (bool) $this->betterNodeFinder->find(
|
||||
(array) $method->stmts,
|
||||
(array) $classMethod->stmts,
|
||||
function (Node $node): ?bool {
|
||||
if (! $node instanceof MethodCall) {
|
||||
return null;
|
||||
|
@ -128,14 +128,14 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
|
||||
return [];
|
||||
}
|
||||
|
||||
/** @var ParameterReflection $parameter */
|
||||
foreach ($parametersAcceptor->getParameters() as $key => $parameter) {
|
||||
/** @var ParameterReflection $parameterReflection */
|
||||
foreach ($parametersAcceptor->getParameters() as $key => $parameterReflection) {
|
||||
// omitted optional parameter
|
||||
if (! isset($node->args[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($parameter->passedByReference()->no()) {
|
||||
if ($parameterReflection->passedByReference()->no()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -130,8 +130,8 @@ PHP
|
||||
$propertyUsageByMethods = [];
|
||||
|
||||
foreach ($privatePropertyNames as $privatePropertyName) {
|
||||
foreach ($class->getMethods() as $method) {
|
||||
$hasProperty = (bool) $this->betterNodeFinder->findFirst($method, function (Node $node) use (
|
||||
foreach ($class->getMethods() as $classMethod) {
|
||||
$hasProperty = (bool) $this->betterNodeFinder->findFirst($classMethod, function (Node $node) use (
|
||||
$privatePropertyName
|
||||
): bool {
|
||||
if (! $node instanceof PropertyFetch) {
|
||||
@ -145,7 +145,7 @@ PHP
|
||||
continue;
|
||||
}
|
||||
|
||||
$isPropertyChangingInMultipleMethodCalls = $this->isPropertyChangingInMultipleMethodCalls($method,
|
||||
$isPropertyChangingInMultipleMethodCalls = $this->isPropertyChangingInMultipleMethodCalls($classMethod,
|
||||
$privatePropertyName);
|
||||
|
||||
if ($isPropertyChangingInMultipleMethodCalls) {
|
||||
@ -153,7 +153,7 @@ PHP
|
||||
}
|
||||
|
||||
/** @var string $classMethodName */
|
||||
$classMethodName = $this->getName($method);
|
||||
$classMethodName = $this->getName($classMethod);
|
||||
$propertyUsageByMethods[$privatePropertyName][] = $classMethodName;
|
||||
}
|
||||
}
|
||||
|
@ -100,13 +100,13 @@ PHP
|
||||
/** @var ReflectionMethod $constructorMethodReflection */
|
||||
$constructorMethodReflection = $this->getNewNodeClassConstructorMethodReflection($node);
|
||||
|
||||
foreach ($constructorMethodReflection->getParameters() as $position => $parameterReflection) {
|
||||
foreach ($constructorMethodReflection->getParameters() as $position => $reflectionParameter) {
|
||||
// argument is already set
|
||||
if (isset($node->args[$position])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classToInstantiate = $this->resolveClassToInstantiateByParameterReflection($parameterReflection);
|
||||
$classToInstantiate = $this->resolveClassToInstantiateByParameterReflection($reflectionParameter);
|
||||
if ($classToInstantiate === null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -38,10 +38,10 @@ final class NewValueObjectFactory
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($valueObjectClass);
|
||||
$propertyValues = [];
|
||||
foreach ($reflectionClass->getProperties() as $propertyReflection) {
|
||||
$propertyReflection->setAccessible(true);
|
||||
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
|
||||
$reflectionProperty->setAccessible(true);
|
||||
|
||||
$propertyValues[] = $propertyReflection->getValue($valueObject);
|
||||
$propertyValues[] = $reflectionProperty->getValue($valueObject);
|
||||
}
|
||||
return $propertyValues;
|
||||
}
|
||||
|
@ -250,8 +250,8 @@ PHP
|
||||
}
|
||||
|
||||
$namesToArgs = [];
|
||||
foreach ($constructorReflectionMethod->getParameters() as $parameterReflection) {
|
||||
$namesToArgs[$parameterReflection->getName()] = $argNodes[$parameterReflection->getPosition()];
|
||||
foreach ($constructorReflectionMethod->getParameters() as $reflectionParameter) {
|
||||
$namesToArgs[$reflectionParameter->getName()] = $argNodes[$reflectionParameter->getPosition()];
|
||||
}
|
||||
|
||||
return $namesToArgs;
|
||||
|
@ -176,15 +176,15 @@ PHP
|
||||
FuncCall $funcCall
|
||||
): ?Node {
|
||||
$fullyQualifiedObjectType = new FullyQualifiedObjectType($argumentFuncCallToMethodCall->getClass());
|
||||
$propertyName = $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType);
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType);
|
||||
|
||||
if ($propertyName === null) {
|
||||
if ($expectedName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$this->addConstructorDependencyToClass($class, $fullyQualifiedObjectType, $propertyName);
|
||||
$this->addConstructorDependencyToClass($class, $fullyQualifiedObjectType, $expectedName->getName());
|
||||
|
||||
$propertyFetchNode = $this->createPropertyFetch('this', $propertyName);
|
||||
$propertyFetchNode = $this->createPropertyFetch('this', $expectedName->getName());
|
||||
|
||||
if (count($funcCall->args) === 0) {
|
||||
if ($argumentFuncCallToMethodCall->getMethodIfNoArgs()) {
|
||||
|
@ -99,8 +99,8 @@ final class RemovedAndAddedFilesProcessor
|
||||
|
||||
private function processDeletedFiles(): void
|
||||
{
|
||||
foreach ($this->removedAndAddedFilesCollector->getRemovedFiles() as $smartFileInfo) {
|
||||
$relativePath = $smartFileInfo->getRelativeFilePathFromDirectory(getcwd());
|
||||
foreach ($this->removedAndAddedFilesCollector->getRemovedFiles() as $removedFile) {
|
||||
$relativePath = $removedFile->getRelativeFilePathFromDirectory(getcwd());
|
||||
|
||||
if ($this->configuration->isDryRun()) {
|
||||
$message = sprintf('File "%s" will be removed', $relativePath);
|
||||
@ -108,7 +108,7 @@ final class RemovedAndAddedFilesProcessor
|
||||
} else {
|
||||
$message = sprintf('File "%s" was removed', $relativePath);
|
||||
$this->symfonyStyle->warning($message);
|
||||
$this->filesystem->remove($smartFileInfo->getRealPath());
|
||||
$this->filesystem->remove($removedFile->getRealPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,13 +67,13 @@ final class ClassConstManipulator
|
||||
}
|
||||
|
||||
$searchInNodes = [$classLike];
|
||||
foreach ($this->classManipulator->getUsedTraits($classLike) as $trait) {
|
||||
$trait = $this->parsedNodeCollector->findTrait((string) $trait);
|
||||
if ($trait === null) {
|
||||
foreach ($this->classManipulator->getUsedTraits($classLike) as $name) {
|
||||
$name = $this->parsedNodeCollector->findTrait((string) $name);
|
||||
if ($name === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$searchInNodes[] = $trait;
|
||||
$searchInNodes[] = $name;
|
||||
}
|
||||
|
||||
return $this->betterNodeFinder->find($searchInNodes, function (Node $node) use ($classConst): bool {
|
||||
|
@ -50,8 +50,8 @@ final class ClassManipulator
|
||||
public function getUsedTraits(ClassLike $classLike): array
|
||||
{
|
||||
$usedTraits = [];
|
||||
foreach ($classLike->getTraitUses() as $stmt) {
|
||||
foreach ($stmt->traits as $trait) {
|
||||
foreach ($classLike->getTraitUses() as $traitUse) {
|
||||
foreach ($traitUse->traits as $trait) {
|
||||
/** @var string $traitName */
|
||||
$traitName = $this->nodeNameResolver->getName($trait);
|
||||
$usedTraits[$traitName] = $trait;
|
||||
|
@ -172,8 +172,8 @@ final class AttributeAwareClassFactoryFactory
|
||||
|
||||
$phpDocParserNodeVariable = new Variable(self::NODE);
|
||||
|
||||
foreach ($constructorReflectionMethod->getParameters() as $parameter) {
|
||||
$parameterName = $parameter->getName();
|
||||
foreach ($constructorReflectionMethod->getParameters() as $reflectionParameter) {
|
||||
$parameterName = $reflectionParameter->getName();
|
||||
|
||||
$new->args[] = new Arg(new PropertyFetch($phpDocParserNodeVariable, $parameterName));
|
||||
}
|
||||
|
@ -44,8 +44,8 @@ final class ValidateFixtureSuffixCommand extends Command
|
||||
{
|
||||
$invalidFilePaths = [];
|
||||
|
||||
foreach ($this->getInvalidFixtureFileInfos() as $fixtureFileInfo) {
|
||||
$invalidFilePaths[] = $fixtureFileInfo->getRelativeFilePathFromCwd();
|
||||
foreach ($this->getInvalidFixtureFileInfos() as $invalidFixtureFileInfo) {
|
||||
$invalidFilePaths[] = $invalidFixtureFileInfo->getRelativeFilePathFromCwd();
|
||||
}
|
||||
|
||||
if (count($invalidFilePaths) > 0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user