From 91a354c080efbfbc4cb0854e2b7afa1518da94bd Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 29 Oct 2020 22:25:35 +0100 Subject: [PATCH] [NetteCodeQuality] Fix ChangeFormArrayAccessToAnnotatedControlVariableRector for in-closure (#4506) * [NetteCodeQuality] Fix ChangeFormArrayAccessToAnnotatedControlVariableRector for in-closure * [ci-review] Rector Rectify * [ci-review] Rector Rectify * [ci-review] Rector Rectify * fix name * fix unknown mixed type on fluent * [ci-review] Rector Rectify Co-authored-by: rector-bot --- .../src/PhpDocInfo/PhpDocInfo.php | 18 ++-- .../src/ParentScopeFinder.php | 9 +- .../FunctionMethodAndClassNodeVisitor.php | 4 + .../src/Imports/ShortNameResolver.php | 6 +- .../UsedClassConstsExtractor.php | 8 +- .../ReturnFluentMethodCallFactory.php | 7 +- ...hainMethodCallToNormalMethodCallRector.php | 4 + ...yInjectionWithRepositoryPropertyRector.php | 4 +- .../src/Naming/ExpectedNameResolver.php | 1 - ...unctionLikeFirstLevelStatementResolver.php | 78 ++++++++++++++++ ...mFetchToAnnotatedControlVariableRector.php | 69 ++------------ .../Fixture/in_on_success_call.php.inc | 57 ++++++++++++ ...VariableToVariableOnFunctionCallRector.php | 26 ++++-- .../Fixture/anonymous_function.php.inc | 6 ++ .../ClassMethodExternalCallNodeAnalyzer.php | 8 +- .../VarInlineAnnotationToAssertRector.php | 4 +- src/Application/RectorApplication.php | 4 +- .../ClassMethodAssignManipulator.php | 14 +-- .../Manipulator/ClassMethodManipulator.php | 6 +- .../cyclic_parameter_reflection.php.inc | 91 +++++++++++++++++++ .../RenameAndFluent/RenameAndFluentTest.php | 30 ++++++ .../config/rename_and_fluent.php | 13 +++ 22 files changed, 356 insertions(+), 111 deletions(-) create mode 100644 rules/nette-code-quality/src/NodeAdding/FunctionLikeFirstLevelStatementResolver.php create mode 100644 rules/nette-code-quality/tests/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector/Fixture/in_on_success_call.php.inc create mode 100644 tests/RectorCombination/RenameAndFluent/Fixture/cyclic_parameter_reflection.php.inc create mode 100644 tests/RectorCombination/RenameAndFluent/RenameAndFluentTest.php create mode 100644 tests/RectorCombination/RenameAndFluent/config/rename_and_fluent.php diff --git a/packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfo.php b/packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfo.php index fbc019ae277..c047af922b9 100644 --- a/packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfo.php +++ b/packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfo.php @@ -180,8 +180,8 @@ final class PhpDocInfo public function getParamType(string $name): Type { - $paramTagValue = $this->getParamTagValueByName($name); - return $this->getTypeOrMixed($paramTagValue); + $attributeAwareParamTagValueNode = $this->getParamTagValueByName($name); + return $this->getTypeOrMixed($attributeAwareParamTagValueNode); } /** @@ -190,8 +190,8 @@ final class PhpDocInfo public function getParamTypes(): array { $paramTypes = []; - foreach ($this->phpDocNode->getParamTagValues() as $paramTagValue) { - $paramTypes[] = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($paramTagValue, $this->node); + foreach ($this->phpDocNode->getParamTagValues() as $paramTagValueNode) { + $paramTypes[] = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($paramTagValueNode, $this->node); } return $paramTypes; @@ -199,12 +199,12 @@ final class PhpDocInfo public function getParamTagValueNodeByName(string $parameterName): ?ParamTagValueNode { - foreach ($this->phpDocNode->getParamTagValues() as $paramTagValue) { - if ($paramTagValue->parameterName !== '$' . $parameterName) { + foreach ($this->phpDocNode->getParamTagValues() as $paramTagValueNode) { + if ($paramTagValueNode->parameterName !== '$' . $parameterName) { continue; } - return $paramTagValue; + return $paramTagValueNode; } return null; @@ -485,9 +485,9 @@ final class PhpDocInfo { $throwsTypes = []; - foreach ($this->phpDocNode->getThrowsTagValues() as $throwsPhpDocNode) { + foreach ($this->phpDocNode->getThrowsTagValues() as $throwsTagValueNode) { $throwsTypes[] = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType( - $throwsPhpDocNode, + $throwsTagValueNode, $this->node ); } diff --git a/packages/node-nesting-scope/src/ParentScopeFinder.php b/packages/node-nesting-scope/src/ParentScopeFinder.php index a16f9276b33..33a73fb7015 100644 --- a/packages/node-nesting-scope/src/ParentScopeFinder.php +++ b/packages/node-nesting-scope/src/ParentScopeFinder.php @@ -18,9 +18,10 @@ final class ParentScopeFinder */ public function find(Node $node): ?Node { - return $node->getAttribute(AttributeKey::METHOD_NODE) - ?? $node->getAttribute(AttributeKey::FUNCTION_NODE) - ?? $node->getAttribute(AttributeKey::CLASS_NODE) - ?? $node->getAttribute(AttributeKey::NAMESPACE_NODE); + return $node->getAttribute(AttributeKey::CLOSURE_NODE) ?? + $node->getAttribute(AttributeKey::FUNCTION_NODE) ?? + $node->getAttribute(AttributeKey::METHOD_NODE) ?? + $node->getAttribute(AttributeKey::CLASS_NODE) ?? + $node->getAttribute(AttributeKey::NAMESPACE_NODE); } } diff --git a/packages/node-type-resolver/src/NodeVisitor/FunctionMethodAndClassNodeVisitor.php b/packages/node-type-resolver/src/NodeVisitor/FunctionMethodAndClassNodeVisitor.php index 3554a4d1d95..7a119b634e1 100644 --- a/packages/node-type-resolver/src/NodeVisitor/FunctionMethodAndClassNodeVisitor.php +++ b/packages/node-type-resolver/src/NodeVisitor/FunctionMethodAndClassNodeVisitor.php @@ -113,6 +113,10 @@ final class FunctionMethodAndClassNodeVisitor extends NodeVisitorAbstract $this->methodName = (string) $this->methodName; } + if ($node instanceof Closure) { + $this->closure = null; + } + return null; } diff --git a/rules/coding-style/src/Imports/ShortNameResolver.php b/rules/coding-style/src/Imports/ShortNameResolver.php index ba8719581d6..a0a26fb8699 100644 --- a/rules/coding-style/src/Imports/ShortNameResolver.php +++ b/rules/coding-style/src/Imports/ShortNameResolver.php @@ -115,9 +115,9 @@ final class ShortNameResolver return $fileInfo->getRealPath(); } - $currentFileInfo = $this->currentFileInfoProvider->getSmartFileInfo(); - if ($currentFileInfo !== null) { - return $currentFileInfo->getRealPath(); + $smartFileInfo = $this->currentFileInfoProvider->getSmartFileInfo(); + if ($smartFileInfo !== null) { + return $smartFileInfo->getRealPath(); } return null; diff --git a/rules/decouple/src/UsedNodesExtractor/UsedClassConstsExtractor.php b/rules/decouple/src/UsedNodesExtractor/UsedClassConstsExtractor.php index 5c4945f8c15..8961700caa8 100644 --- a/rules/decouple/src/UsedNodesExtractor/UsedClassConstsExtractor.php +++ b/rules/decouple/src/UsedNodesExtractor/UsedClassConstsExtractor.php @@ -70,14 +70,14 @@ final class UsedClassConstsExtractor private function getClassConstByName(Class_ $class, string $classConstName): ClassConst { $classConstantNames = []; - foreach ($class->getConstants() as $constant) { - $classConstantNames[] = $this->nodeNameResolver->getName($constant); + foreach ($class->getConstants() as $classConst) { + $classConstantNames[] = $this->nodeNameResolver->getName($classConst); - if (! $this->nodeNameResolver->isName($constant, $classConstName)) { + if (! $this->nodeNameResolver->isName($classConst, $classConstName)) { continue; } - return $constant; + return $classConst; } $className = $this->nodeNameResolver->getName($class); diff --git a/rules/defluent/src/NodeFactory/ReturnFluentMethodCallFactory.php b/rules/defluent/src/NodeFactory/ReturnFluentMethodCallFactory.php index ac629ab8c6c..3c6736df5e0 100644 --- a/rules/defluent/src/NodeFactory/ReturnFluentMethodCallFactory.php +++ b/rules/defluent/src/NodeFactory/ReturnFluentMethodCallFactory.php @@ -7,6 +7,7 @@ namespace Rector\Defluent\NodeFactory; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Variable; +use PHPStan\Type\ObjectType; use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallRootExtractor; use Rector\Defluent\ValueObject\FirstAssignFluentCall; use Rector\Defluent\ValueObject\FluentMethodCalls; @@ -40,7 +41,7 @@ final class ReturnFluentMethodCallFactory $this->propertyNaming = $propertyNaming; } - public function createFromFluentMethodCalls(FluentMethodCalls $fluentMethodCalls): FirstAssignFluentCall + public function createFromFluentMethodCalls(FluentMethodCalls $fluentMethodCalls): ?FirstAssignFluentCall { $rootMethodCall = $fluentMethodCalls->getRootMethodCall(); @@ -58,6 +59,10 @@ final class ReturnFluentMethodCallFactory // we need a variable to assign the stuff into // the method call, does not belong to the $staticType = $this->nodeTypeResolver->getStaticType($rootMethodCall); + if (! $staticType instanceof ObjectType) { + return null; + } + $variableName = $this->propertyNaming->fqnToVariableName($staticType); $assignExpr = new Variable($variableName); } diff --git a/rules/defluent/src/Rector/Return_/ReturnFluentChainMethodCallToNormalMethodCallRector.php b/rules/defluent/src/Rector/Return_/ReturnFluentChainMethodCallToNormalMethodCallRector.php index e8765ebcafd..d17b8529197 100644 --- a/rules/defluent/src/Rector/Return_/ReturnFluentChainMethodCallToNormalMethodCallRector.php +++ b/rules/defluent/src/Rector/Return_/ReturnFluentChainMethodCallToNormalMethodCallRector.php @@ -125,6 +125,10 @@ CODE_SAMPLE $fluentMethodCalls ); + if ($firstAssignFluentCall === null) { + return []; + } + // should be skipped? if ($this->fluentMethodCallSkipper->shouldSkipFirstAssignFluentCall($firstAssignFluentCall)) { return []; diff --git a/rules/doctrine/src/Rector/ClassMethod/ServiceEntityRepositoryConstructorToDependencyInjectionWithRepositoryPropertyRector.php b/rules/doctrine/src/Rector/ClassMethod/ServiceEntityRepositoryConstructorToDependencyInjectionWithRepositoryPropertyRector.php index 9ca7e790309..b1c844cdc12 100644 --- a/rules/doctrine/src/Rector/ClassMethod/ServiceEntityRepositoryConstructorToDependencyInjectionWithRepositoryPropertyRector.php +++ b/rules/doctrine/src/Rector/ClassMethod/ServiceEntityRepositoryConstructorToDependencyInjectionWithRepositoryPropertyRector.php @@ -181,7 +181,7 @@ CODE_SAMPLE private function addRepositoryProperty(Class_ $class, Expr $entityReferenceExpr): void { - $repositoryPropertyType = $this->repositoryTypeFactory->createRepositoryPropertyType($entityReferenceExpr); - $this->addPropertyToClass($class, $repositoryPropertyType, 'repository'); + $genericObjectType = $this->repositoryTypeFactory->createRepositoryPropertyType($entityReferenceExpr); + $this->addPropertyToClass($class, $genericObjectType, 'repository'); } } diff --git a/rules/naming/src/Naming/ExpectedNameResolver.php b/rules/naming/src/Naming/ExpectedNameResolver.php index bd8b9503100..842a99a0a33 100644 --- a/rules/naming/src/Naming/ExpectedNameResolver.php +++ b/rules/naming/src/Naming/ExpectedNameResolver.php @@ -200,7 +200,6 @@ final class ExpectedNameResolver } $returnedType = $this->nodeTypeResolver->getStaticType($expr); - if ($returnedType->isIterable()->no()) { return null; } diff --git a/rules/nette-code-quality/src/NodeAdding/FunctionLikeFirstLevelStatementResolver.php b/rules/nette-code-quality/src/NodeAdding/FunctionLikeFirstLevelStatementResolver.php new file mode 100644 index 00000000000..477403bcda3 --- /dev/null +++ b/rules/nette-code-quality/src/NodeAdding/FunctionLikeFirstLevelStatementResolver.php @@ -0,0 +1,78 @@ +parentScopeFinder = $parentScopeFinder; + } + + public function resolveFirstLevelStatement(Node $node): Node + { + $multiplierClosure = $this->matchMultiplierClosure($node); + $functionLike = $multiplierClosure ?? $this->parentScopeFinder->find($node); + + /** @var ClassMethod|Closure|null $functionLike */ + if ($functionLike === null) { + throw new ShouldNotHappenException(); + } + + $currentStatement = $node->getAttribute(AttributeKey::CURRENT_STATEMENT); + if (! $currentStatement instanceof Node) { + throw new ShouldNotHappenException(); + } + + while (! in_array($currentStatement, (array) $functionLike->stmts, true)) { + $parent = $currentStatement->getAttribute(AttributeKey::PARENT_NODE); + if (! $parent instanceof Node) { + throw new ShouldNotHappenException(); + } + + $currentStatement = $parent->getAttribute(AttributeKey::CURRENT_STATEMENT); + } + + return $currentStatement; + } + + /** + * Form might be costructured inside private closure for multiplier + * @see https://doc.nette.org/en/3.0/multiplier + */ + private function matchMultiplierClosure(Node $node): ?Closure + { + /** @var Closure|null $closure */ + $closure = $node->getAttribute(AttributeKey::CLOSURE_NODE); + if ($closure === null) { + return null; + } + + $parent = $closure->getAttribute(AttributeKey::PARENT_NODE); + if (! $parent instanceof Arg) { + return null; + } + + $parentParent = $parent->getAttribute(AttributeKey::PARENT_NODE); + if (! $parentParent instanceof New_) { + return null; + } + + return $closure; + } +} diff --git a/rules/nette-code-quality/src/Rector/ArrayDimFetch/AbstractArrayDimFetchToAnnotatedControlVariableRector.php b/rules/nette-code-quality/src/Rector/ArrayDimFetch/AbstractArrayDimFetchToAnnotatedControlVariableRector.php index c4fea799f74..5ad2f8f17cb 100644 --- a/rules/nette-code-quality/src/Rector/ArrayDimFetch/AbstractArrayDimFetchToAnnotatedControlVariableRector.php +++ b/rules/nette-code-quality/src/Rector/ArrayDimFetch/AbstractArrayDimFetchToAnnotatedControlVariableRector.php @@ -4,20 +4,16 @@ declare(strict_types=1); namespace Rector\NetteCodeQuality\Rector\ArrayDimFetch; -use PhpParser\Node; -use PhpParser\Node\Arg; use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\PhpDocManipulator\VarAnnotationManipulator; -use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\Rector\AbstractRector; use Rector\NetteCodeQuality\Naming\NetteControlNaming; +use Rector\NetteCodeQuality\NodeAdding\FunctionLikeFirstLevelStatementResolver; use Rector\NetteCodeQuality\NodeAnalyzer\ControlDimFetchAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -46,17 +42,24 @@ abstract class AbstractArrayDimFetchToAnnotatedControlVariableRector extends Abs */ private $alreadyInitializedAssignsClassMethodObjectHashes = []; + /** + * @var FunctionLikeFirstLevelStatementResolver + */ + private $functionLikeFirstLevelStatementResolver; + /** * @required */ public function autowireAbstractArrayDimFetchToAnnotatedControlVariableRector( VarAnnotationManipulator $varAnnotationManipulator, ControlDimFetchAnalyzer $controlDimFetchAnalyzer, - NetteControlNaming $netteControlNaming + NetteControlNaming $netteControlNaming, + FunctionLikeFirstLevelStatementResolver $functionLikeFirstLevelStatementResolver ): void { $this->controlDimFetchAnalyzer = $controlDimFetchAnalyzer; $this->netteControlNaming = $netteControlNaming; $this->varAnnotationManipulator = $varAnnotationManipulator; + $this->functionLikeFirstLevelStatementResolver = $functionLikeFirstLevelStatementResolver; } /** @@ -78,7 +81,7 @@ abstract class AbstractArrayDimFetchToAnnotatedControlVariableRector extends Abs $assignExpression = $this->createAnnotatedAssignExpression($variableName, $arrayDimFetch, $controlObjectType); - $currentStatement = $this->getClassMethodFirstLevelStatement($arrayDimFetch); + $currentStatement = $this->functionLikeFirstLevelStatementResolver->resolveFirstLevelStatement($arrayDimFetch); $this->addNodeBeforeNode($assignExpression, $currentStatement); } @@ -133,33 +136,6 @@ abstract class AbstractArrayDimFetchToAnnotatedControlVariableRector extends Abs return $assignExpression; } - private function getClassMethodFirstLevelStatement(Node $node): Node - { - $multiplierClosure = $this->matchMultiplierClosure($node); - $functionLike = $multiplierClosure ?? $node->getAttribute(AttributeKey::METHOD_NODE); - - /** @var ClassMethod|Closure|null $functionLike */ - if ($functionLike === null) { - throw new ShouldNotHappenException(); - } - - $currentStatement = $node->getAttribute(AttributeKey::CURRENT_STATEMENT); - if (! $currentStatement instanceof Node) { - throw new ShouldNotHappenException(); - } - - while (! in_array($currentStatement, (array) $functionLike->stmts, true)) { - $parent = $currentStatement->getAttribute(AttributeKey::PARENT_NODE); - if (! $parent instanceof Node) { - throw new ShouldNotHappenException(); - } - - $currentStatement = $parent->getAttribute(AttributeKey::CURRENT_STATEMENT); - } - - return $currentStatement; - } - private function createAssignExpression(string $variableName, ArrayDimFetch $arrayDimFetch): Expression { $variable = new Variable($variableName); @@ -168,29 +144,4 @@ abstract class AbstractArrayDimFetchToAnnotatedControlVariableRector extends Abs return new Expression($assign); } - - /** - * Form might be costructured inside private closure for multiplier - * @see https://doc.nette.org/en/3.0/multiplier - */ - private function matchMultiplierClosure(Node $node): ?Closure - { - /** @var Closure|null $closure */ - $closure = $node->getAttribute(AttributeKey::CLOSURE_NODE); - if ($closure === null) { - return null; - } - - $parent = $closure->getAttribute(AttributeKey::PARENT_NODE); - if (! $parent instanceof Arg) { - return null; - } - - $parentParent = $parent->getAttribute(AttributeKey::PARENT_NODE); - if (! $parentParent instanceof New_) { - return null; - } - - return $closure; - } } diff --git a/rules/nette-code-quality/tests/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector/Fixture/in_on_success_call.php.inc b/rules/nette-code-quality/tests/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector/Fixture/in_on_success_call.php.inc new file mode 100644 index 00000000000..c186d45ac3b --- /dev/null +++ b/rules/nette-code-quality/tests/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector/Fixture/in_on_success_call.php.inc @@ -0,0 +1,57 @@ +makeForm(); + + $onSuccess = function (Form $form) { + $form['email_else']->value = 'hey@hi.hello'; + }; + } + + public function makeForm(): Form + { + $form = new Form(); + $form->addText('email_else', 'Email'); + + return $form; + } +} + +?> +----- +makeForm(); + + $onSuccess = function (Form $form) { + /** @var \Nette\Forms\Controls\TextInput $emailElseControl */ + $emailElseControl = $form['email_else']; + $emailElseControl->value = 'hey@hi.hello'; + }; + } + + public function makeForm(): Form + { + $form = new Form(); + $form->addText('email_else', 'Email'); + + return $form; + } +} + +?> diff --git a/rules/php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php b/rules/php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php index 7aa888da79f..ee121e96bb1 100644 --- a/rules/php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php +++ b/rules/php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php @@ -26,6 +26,7 @@ use Rector\Core\Rector\AbstractRector; use Rector\Core\RectorDefinition\CodeSample; use Rector\Core\RectorDefinition\RectorDefinition; use Rector\NetteKdyby\Naming\VariableNaming; +use Rector\NodeNestingScope\ParentScopeFinder; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Php70\ValueObject\VariableAssignPair; @@ -46,10 +47,19 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector */ private $variableNaming; - public function __construct(CallReflectionResolver $callReflectionResolver, VariableNaming $variableNaming) - { + /** + * @var ParentScopeFinder + */ + private $parentScopeFinder; + + public function __construct( + CallReflectionResolver $callReflectionResolver, + VariableNaming $variableNaming, + ParentScopeFinder $parentScopeFinder + ) { $this->callReflectionResolver = $callReflectionResolver; $this->variableNaming = $variableNaming; + $this->parentScopeFinder = $parentScopeFinder; } public function getDefinition(): RectorDefinition @@ -78,7 +88,10 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector return null; } - $scopeNode = $this->resolveScopeNode($node); + $scopeNode = $this->parentScopeFinder->find($node); + if ($scopeNode === null) { + return null; + } $currentScope = $scopeNode->getAttribute(AttributeKey::SCOPE); if (! $currentScope instanceof MutatingScope) { @@ -151,13 +164,6 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector return $arguments; } - private function resolveScopeNode(Node $node): Node - { - return $node->getAttribute(AttributeKey::METHOD_NODE) ?? - $node->getAttribute(AttributeKey::FUNCTION_NODE) ?? - $node->getAttribute(AttributeKey::CLOSURE_NODE); - } - private function getReplacementsFor(Expr $expr, MutatingScope $mutatingScope, Node $scopeNode): VariableAssignPair { /** @var Assign|AssignOp|AssignRef $expr */ diff --git a/rules/php70/tests/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector/Fixture/anonymous_function.php.inc b/rules/php70/tests/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector/Fixture/anonymous_function.php.inc index 5f2828ff44e..bb078bef637 100644 --- a/rules/php70/tests/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector/Fixture/anonymous_function.php.inc +++ b/rules/php70/tests/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector/Fixture/anonymous_function.php.inc @@ -5,8 +5,11 @@ namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCall function anonymousFunction() { $anonymousFunction = function (&$bar) {}; + $anonymousFunction(bar()); + $staticAnonymousFunction = static function (&$bar) {}; + $staticAnonymousFunction(bar()); } @@ -20,9 +23,12 @@ function anonymousFunction() { $anonymousFunction = function (&$bar) {}; $bar = bar(); + $anonymousFunction($bar); + $staticAnonymousFunction = static function (&$bar) {}; $bar2 = bar(); + $staticAnonymousFunction($bar2); } diff --git a/rules/privatization/src/NodeAnalyzer/ClassMethodExternalCallNodeAnalyzer.php b/rules/privatization/src/NodeAnalyzer/ClassMethodExternalCallNodeAnalyzer.php index bbe879193b6..a7fa7042820 100644 --- a/rules/privatization/src/NodeAnalyzer/ClassMethodExternalCallNodeAnalyzer.php +++ b/rules/privatization/src/NodeAnalyzer/ClassMethodExternalCallNodeAnalyzer.php @@ -117,19 +117,19 @@ final class ClassMethodExternalCallNodeAnalyzer private function isEventSubscriberMethod(ClassMethod $classMethod, string $methodName): bool { - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classNode instanceof Class_) { + $classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE); + if (! $classLike instanceof Class_) { return false; } if (! $this->nodeTypeResolver->isObjectType( - $classNode, + $classLike, 'Symfony\Component\EventDispatcher\EventSubscriberInterface') ) { return false; } - $getSubscribedEventsClassMethod = $classNode->getMethod('getSubscribedEvents'); + $getSubscribedEventsClassMethod = $classLike->getMethod('getSubscribedEvents'); if ($getSubscribedEventsClassMethod === null) { return false; } diff --git a/rules/strict-code-quality/src/Rector/Stmt/VarInlineAnnotationToAssertRector.php b/rules/strict-code-quality/src/Rector/Stmt/VarInlineAnnotationToAssertRector.php index 98705b5d88d..ae1fb5be133 100644 --- a/rules/strict-code-quality/src/Rector/Stmt/VarInlineAnnotationToAssertRector.php +++ b/rules/strict-code-quality/src/Rector/Stmt/VarInlineAnnotationToAssertRector.php @@ -199,8 +199,8 @@ CODE_SAMPLE } if ($type instanceof FloatType) { - $isFloat = $this->createFuncCall('is_float', [$variable]); - return $this->createFuncCall(self::ASSERT, [$isFloat]); + $funcCall = $this->createFuncCall('is_float', [$variable]); + return $this->createFuncCall(self::ASSERT, [$funcCall]); } if ($type instanceof StringType) { diff --git a/src/Application/RectorApplication.php b/src/Application/RectorApplication.php index 20dde3305dd..69104461d8b 100644 --- a/src/Application/RectorApplication.php +++ b/src/Application/RectorApplication.php @@ -270,12 +270,12 @@ final class RectorApplication return; } - $oldContent = $fileInfo->getContents(); + $contents = $fileInfo->getContents(); $newContent = $this->configuration->isDryRun() ? $this->fileProcessor->printToString($fileInfo) : $this->fileProcessor->printToFile($fileInfo); - $this->errorAndDiffCollector->addFileDiff($fileInfo, $newContent, $oldContent); + $this->errorAndDiffCollector->addFileDiff($fileInfo, $newContent, $contents); } /** diff --git a/src/PhpParser/Node/Manipulator/ClassMethodAssignManipulator.php b/src/PhpParser/Node/Manipulator/ClassMethodAssignManipulator.php index 65f665b8895..c6ad3868cf5 100644 --- a/src/PhpParser/Node/Manipulator/ClassMethodAssignManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassMethodAssignManipulator.php @@ -325,13 +325,13 @@ final class ClassMethodAssignManipulator return false; } - /** @var ParameterReflection $parameter */ - foreach ($parametersAcceptor->getParameters() as $parameter) { - if ($parameter->getName() !== $variableName) { + /** @var ParameterReflection $parameterReflection */ + foreach ($parametersAcceptor->getParameters() as $parameterReflection) { + if ($parameterReflection->getName() !== $variableName) { continue; } - return $parameter->passedByReference() + return $parameterReflection->passedByReference() ->yes(); } @@ -375,13 +375,13 @@ final class ClassMethodAssignManipulator return false; } - /** @var ParameterReflection $parameter */ - foreach ($parametersAcceptor->getParameters() as $parameterPosition => $parameter) { + /** @var ParameterReflection $parameterReflection */ + foreach ($parametersAcceptor->getParameters() as $parameterPosition => $parameterReflection) { if ($parameterPosition !== $argumentPosition) { continue; } - return $parameter->passedByReference() + return $parameterReflection->passedByReference() ->yes(); } diff --git a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php index 2474de81e53..80be5fdef5b 100644 --- a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php @@ -92,12 +92,12 @@ final class ClassMethodManipulator return false; } - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classNode instanceof Class_) { + $classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE); + if (! $classLike instanceof Class_) { return false; } - return $classMethod->isPrivate() || (! $classNode->isFinal() && $classMethod->isProtected()); + return $classMethod->isPrivate() || (! $classLike->isFinal() && $classMethod->isProtected()); } public function hasParentMethodOrInterfaceMethod(ClassMethod $classMethod, ?string $methodName = null): bool diff --git a/tests/RectorCombination/RenameAndFluent/Fixture/cyclic_parameter_reflection.php.inc b/tests/RectorCombination/RenameAndFluent/Fixture/cyclic_parameter_reflection.php.inc new file mode 100644 index 00000000000..dc28fc14fcc --- /dev/null +++ b/tests/RectorCombination/RenameAndFluent/Fixture/cyclic_parameter_reflection.php.inc @@ -0,0 +1,91 @@ +callReflectionResolver = $callReflectionResolver; + } + + private function isParameterReferencedInMethodReflection(New_ $new, int $argumentPosition): bool + { + $methodReflection = $this->callReflectionResolver->resolveConstructor($new); + $parametersAcceptor = $this->callReflectionResolver->resolveParametersAcceptor($methodReflection, $new); + + if ($parametersAcceptor === null) { + return false; + } + + /** @var ParameterReflection $parameter */ + foreach ($parametersAcceptor->getParameters() as $parameterPosition => $parameter) { + if ($parameterPosition !== $argumentPosition) { + continue; + } + + return $parameter->passedByReference()->yes(); + } + + return false; + } +} + +?> +----- +callReflectionResolver = $callReflectionResolver; + } + + private function isParameterReferencedInMethodReflection(New_ $new, int $argumentPosition): bool + { + $methodReflection = $this->callReflectionResolver->resolveConstructor($new); + $parametersAcceptor = $this->callReflectionResolver->resolveParametersAcceptor($methodReflection, $new); + + if ($parametersAcceptor === null) { + return false; + } + + /** @var ParameterReflection $parameterReflection */ + foreach ($parametersAcceptor->getParameters() as $parameterPosition => $parameterReflection) { + if ($parameterPosition !== $argumentPosition) { + continue; + } + + return $parameterReflection->passedByReference()->yes(); + } + + return false; + } +} + +?> diff --git a/tests/RectorCombination/RenameAndFluent/RenameAndFluentTest.php b/tests/RectorCombination/RenameAndFluent/RenameAndFluentTest.php new file mode 100644 index 00000000000..05f6671233c --- /dev/null +++ b/tests/RectorCombination/RenameAndFluent/RenameAndFluentTest.php @@ -0,0 +1,30 @@ +doTestFileInfo($fileInfo); + } + + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + protected function provideConfigFileInfo(): ?SmartFileInfo + { + return new SmartFileInfo(__DIR__ . '/config/rename_and_fluent.php'); + } +} diff --git a/tests/RectorCombination/RenameAndFluent/config/rename_and_fluent.php b/tests/RectorCombination/RenameAndFluent/config/rename_and_fluent.php new file mode 100644 index 00000000000..e404231762b --- /dev/null +++ b/tests/RectorCombination/RenameAndFluent/config/rename_and_fluent.php @@ -0,0 +1,13 @@ +services(); + $services->set(ReturnFluentChainMethodCallToNormalMethodCallRector::class); + $services->set(RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class); +};