diff --git a/.github/workflows/phpstan.yaml b/.github/workflows/phpstan.yaml index 3872a57941f4..699d4e70e02b 100644 --- a/.github/workflows/phpstan.yaml +++ b/.github/workflows/phpstan.yaml @@ -18,4 +18,4 @@ jobs: tools: cs2pr - run: composer install --no-progress # turn the phpstan errors (formatted in checkstyle-format) into github pull request check annotations - - run: composer phpstan -- --error-format=checkstyle | cs2pr + - run: composer phpstan # -- --error-format=checkstyle | cs2pr diff --git a/compiler/build/scoper.inc.php b/compiler/build/scoper.inc.php index b33814df1648..145f30a58df0 100644 --- a/compiler/build/scoper.inc.php +++ b/compiler/build/scoper.inc.php @@ -18,7 +18,7 @@ foreach ($stubFinder->getIterator() as $fileInfo) { // mirrors https://github.com/phpstan/phpstan-src/commit/04f777bc4445725d17dac65c989400485454b145 - if ($file->getPathName() === '../../vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php') { + if ($fileInfo->getPathName() === '../../vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php') { continue; } diff --git a/composer.json b/composer.json index 07958d6ba50c..e34a1687b035 100644 --- a/composer.json +++ b/composer.json @@ -102,6 +102,7 @@ "Rector\\Symfony\\": "packages/symfony/src", "Rector\\Twig\\": "packages/twig/src", "Rector\\TypeDeclaration\\": "packages/type-declaration/src", + "Rector\\VendorLocker\\": "packages/vendor-locker/src", "Rector\\ZendToSymfony\\": "packages/zend-to-symfony/src", "Rector\\RectorGenerator\\": "packages/rector-generator/src", "Rector\\StrictCodeQuality\\": "packages/strict-code-quality/src", diff --git a/docs/AllRectorsOverview.md b/docs/AllRectorsOverview.md index 1d4c4f3b6778..cfe3c619b21f 100644 --- a/docs/AllRectorsOverview.md +++ b/docs/AllRectorsOverview.md @@ -4512,7 +4512,9 @@ services: ↓ ```diff - class SomeServiceTest extends \PHPUnit\Framework\TestCase + use PHPUnit\Framework\TestCase; + + class SomeServiceTest extends TestCase { - public function test() + /** @@ -8781,12 +8783,11 @@ Change $this->_view->assign = 5; to $this->render("...", $templateData); public function someAction() { - $this->_view->value = 5; --} + $templateData = []; + $templateData['value']; = 5; + + return $this->render("...", $templateData); -+} + } ```
diff --git a/ecs.yaml b/ecs.yaml index 1212ba0260c5..039d02d5b67a 100644 --- a/ecs.yaml +++ b/ecs.yaml @@ -73,61 +73,19 @@ parameters: # hidden API - 'src/Rector/AbstractRector.php' - # @todo resolve!!! Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff: - - 'src/NodeContainer/NodeCollector/ParsedFunctionLikeNodesByType.php' - - 'src/NodeContainer/NodeCollector/ParsedFunctionLikeNodeCollector.php' - - 'packages/solid/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php' - - 'packages/type-declaration/src/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php' - - 'packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php' - - 'packages/minimal-scope/src/Rector/Class_/ChangeLocalPropertyToVariableRector.php' - - 'packages/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php' - # solve later - - 'src/Console/Command/ScreenFileCommand.php' - - 'packages/doctrine/src/Rector/ClassMethod/AddMethodCallBasedParamTypeRector.php' - - 'packages/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php' - - 'packages/node-type-resolver/src/NodeTypeResolver.php' - - 'packages/node-type-resolver/src/PerNodeTypeResolver/VariableTypeResolver.php' - - 'packages/php-71/src/Rector/FuncCall/RemoveExtraParametersRector.php' - - 'packages/solid/src/Analyzer/ClassConstantFetchAnalyzer.php' - # tough logic - - 'packages/autodiscovery/src/Analyzer/ClassAnalyzer.php' - - 'packages/coding-style/src/Imports/ImportSkipper.php' - - 'packages/phpunit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php' - - 'packages/better-php-doc-parser/src/Ast/PhpDoc/*/*TagValueNode.php' - - 'packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/FqnNamePhpDocNodeDecorator.php' - - 'packages/node-type-resolver/src/PHPStan/Type/StaticTypeAnalyzer.php' - - 'src/NodeContainer/ParsedNodesByType.php' - - - 'packages/phpstan-static-type-mapper/src/PHPStanStaticTypeMapper.php' - - 'packages/node-type-resolver/src/StaticTypeMapper.php' - - - 'packages/phpstan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php' - - 'packages/architecture/src/Rector/Class_/ConstructorInjectionToActionInjectionRector.php' - - 'src/PhpParser/Node/Commander/NodeRemovingCommander.php' - - 'packages/better-php-doc-parser/src/*' - - 'packages/symfony/src/Rector/Class_/MakeCommandLazyRector.php' - - 'packages/legacy/src/Rector/ClassMethod/ChangeSingletonToServiceRector.php' - - 'packages/coding-style/src/Rector/Use_/RemoveUnusedAliasRector.php' - - 'packages/nette-to-symfony/src/Route/RouteInfoFactory.php' - - 'utils/*/DumpNodesCommand.php' - - 'packages/code-quality/src/Rector/Identical/SimplifyBoolIdenticalTrueRector.php' - - 'packages/better-php-doc-parser/src/Attributes/Ast/AttributeAwareNodeFactory.php' - - 'packages/laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php' - - 'packages/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php' - - 'packages/nette-tester-to-phpunit/src/AssertManipulator.php' - - 'packages/legacy/src/NodeAnalyzer/SingletonClassMethodAnalyzer.php' - - 'src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php' - - 'src/PhpParser/Node/Resolver/NameResolver.php' - - 'src/Rector/MethodBody/NormalToFluentRector.php' - - 'src/Rector/AbstractRector/ComplexRemovalTrait.php' - - 'src/PhpParser/Node/Manipulator/IfManipulator.php' - - 'packages/type-declaration/src/VendorLock/VendorLockResolver.php' - - 'packages/type-declaration/src/PhpParserTypeAnalyzer.php' - - 'packages/dead-code/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php' - # aliases - - 'packages/coding-style/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php' - + # todo + - "packages/node-type-resolver/src/NodeTypeResolver.php" + - "packages/better-php-doc-parser/src/Printer/OriginalSpacingRestorer.php" + # @todo split to multiple rectors + - "packages/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php" + + - "packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php" + - "packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php" + - "packages/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php" + + # per node logic + - 'utils/DocumentationGenerator/src/Command/DumpNodesCommand.php' # copied 3rd party logic - 'packages/php-70/src/EregToPcreTransformer.php' # dev diff --git a/packages/architecture/src/Rector/Class_/ConstructorInjectionToActionInjectionRector.php b/packages/architecture/src/Rector/Class_/ConstructorInjectionToActionInjectionRector.php index d48fc8c8df78..38bc413d27e2 100644 --- a/packages/architecture/src/Rector/Class_/ConstructorInjectionToActionInjectionRector.php +++ b/packages/architecture/src/Rector/Class_/ConstructorInjectionToActionInjectionRector.php @@ -112,22 +112,13 @@ public function refactor(Node $node): ?Node { $this->reset(); - // only in controllers - if (! $this->isName($node, '*Controller')) { - return null; - } - - if ($node->isAbstract()) { - return null; - } - - $constructMethod = $node->getMethod('__construct'); - // no constructor, nothing to do - if ($constructMethod === null) { + if ($this->shouldSkip($node)) { return null; } // traverse constructor dependencies and names of their properties + /** @var ClassMethod $constructMethod */ + $constructMethod = $node->getMethod('__construct'); $this->collectPropertyFetchToParams($constructMethod); // replace them in property fetches with particular class methods and use variable instead @@ -220,23 +211,20 @@ private function changePropertyUsageToParameter(ClassMethod $classMethod, string $param, &$currentlyAddedLocalVariables ): ?Variable { - if (! $node instanceof PropertyFetch) { + if ($this->shouldSkipClassMethod($node)) { return null; } - if (! $this->isName($node->var, 'this')) { + /** @var PropertyFetch $node */ + if (! $this->isName($node, $propertyName)) { return null; } - if ($this->isName($node, $propertyName)) { - $currentlyAddedLocalVariables[] = $param; + $currentlyAddedLocalVariables[] = $param; - /** @var string $paramName */ - $paramName = $this->getName($param); - return new Variable($paramName); - } - - return null; + /** @var string $paramName */ + $paramName = $this->getName($param); + return new Variable($paramName); }); foreach ($currentlyAddedLocalVariables as $param) { @@ -330,4 +318,30 @@ private function removeConstructIfEmpty(Class_ $class, ClassMethod $constructCla $this->removeNodeFromStatements($class, $constructClassMethod); } + + private function shouldSkipClassMethod(Node $node): bool + { + if (! $node instanceof PropertyFetch) { + return true; + } + + return ! $this->isName($node->var, 'this'); + } + + private function shouldSkip(Class_ $class): bool + { + // only in controllers + if (! $this->isName($class, '*Controller')) { + return true; + } + + if ($class->isAbstract()) { + return true; + } + + $constructMethod = $class->getMethod('__construct'); + // no constructor, nothing to do + + return $constructMethod === null; + } } diff --git a/packages/autodiscovery/src/Analyzer/ClassAnalyzer.php b/packages/autodiscovery/src/Analyzer/ClassAnalyzer.php index 1486111e1950..34b9111ce1f5 100644 --- a/packages/autodiscovery/src/Analyzer/ClassAnalyzer.php +++ b/packages/autodiscovery/src/Analyzer/ClassAnalyzer.php @@ -10,7 +10,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\BetterPhpDocParser\PhpDocNode\JMS\SerializerTypeTagValueNode; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -22,9 +22,9 @@ final class ClassAnalyzer private $valueObjectStatusByClassName = []; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver @@ -37,11 +37,11 @@ final class ClassAnalyzer private $parsedNodeCollector; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ParsedNodeCollector $parsedNodeCollector, NodeTypeResolver $nodeTypeResolver ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parsedNodeCollector = $parsedNodeCollector; $this->nodeTypeResolver = $nodeTypeResolver; } @@ -52,7 +52,8 @@ public function isValueObjectClass(Class_ $class): bool return false; } - $className = $this->nameResolver->getName($class); + /** @var string $className */ + $className = $this->nodeNameResolver->getName($class); if (isset($this->valueObjectStatusByClassName[$className])) { return $this->valueObjectStatusByClassName[$className]; @@ -61,15 +62,7 @@ public function isValueObjectClass(Class_ $class): bool $constructClassMethod = $class->getMethod('__construct'); if ($constructClassMethod === null) { - // A. has all properties with serialize? - if ($this->hasAllPropertiesWithSerialize($class)) { - $this->valueObjectStatusByClassName[$className] = true; - return true; - } - - // probably not a value object - $this->valueObjectStatusByClassName[$className] = false; - return false; + return $this->analyseWithoutConstructor($class, $className); } // resolve constructor types @@ -116,4 +109,17 @@ private function hasAllPropertiesWithSerialize(Class_ $class) return true; } + + private function analyseWithoutConstructor(Class_ $class, ?string $className): bool + { + // A. has all properties with serialize? + if ($this->hasAllPropertiesWithSerialize($class)) { + $this->valueObjectStatusByClassName[$className] = true; + return true; + } + + // probably not a value object + $this->valueObjectStatusByClassName[$className] = false; + return false; + } } diff --git a/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php b/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php index 206f4e09d30f..38a22be40b32 100644 --- a/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php +++ b/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php @@ -9,7 +9,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\ClassExistenceStaticHelper; use Rector\NodeTypeResolver\Node\AttributeKey; use ReflectionClass; @@ -25,14 +25,14 @@ final class NodeAnnotationReader private $reader; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(Reader $reader, NameResolver $nameResolver) + public function __construct(Reader $reader, NodeNameResolver $nodeNameResolver) { $this->reader = $reader; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -44,7 +44,7 @@ public function readMethodAnnotation(ClassMethod $classMethod, string $annotatio $className = $classMethod->getAttribute(AttributeKey::CLASS_NAME); /** @var string $methodName */ - $methodName = $this->nameResolver->getName($classMethod); + $methodName = $this->nodeNameResolver->getName($classMethod); $reflectionMethod = new ReflectionMethod($className, $methodName); @@ -82,7 +82,7 @@ public function readPropertyAnnotation(Property $property, string $annotationCla private function createClassReflectionFromNode(Class_ $class): ReflectionClass { /** @var string $className */ - $className = $this->nameResolver->getName($class); + $className = $this->nodeNameResolver->getName($class); return new ReflectionClass($className); } @@ -90,7 +90,7 @@ private function createClassReflectionFromNode(Class_ $class): ReflectionClass private function createPropertyReflectionFromPropertyNode(Property $property): ?ReflectionProperty { /** @var string $propertyName */ - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); /** @var string|null $className */ $className = $property->getAttribute(AttributeKey::CLASS_NAME); diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php index 633981d520b0..ed1891351492 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/ColumnTagValueNode.php @@ -113,20 +113,20 @@ public function __toString(): string $contentItems['scale'] = sprintf('scale=%s', $this->scale); } - if ($this->unique !== null) { - $contentItems['unique'] = sprintf('unique=%s', $this->unique ? 'true' : 'false'); - } - - if ($this->nullable !== null) { - $contentItems['nullable'] = sprintf('nullable=%s', $this->nullable ? 'true' : 'false'); + if ($this->columnDefinition !== null) { + $contentItems['columnDefinition'] = sprintf('columnDefinition="%s"', $this->columnDefinition); } if ($this->options) { $contentItems['options'] = $this->printArrayItem($this->options, 'options'); } - if ($this->columnDefinition !== null) { - $contentItems['columnDefinition'] = sprintf('columnDefinition="%s"', $this->columnDefinition); + if ($this->unique !== null) { + $contentItems['unique'] = sprintf('unique=%s', $this->unique ? 'true' : 'false'); + } + + if ($this->nullable !== null) { + $contentItems['nullable'] = sprintf('nullable=%s', $this->nullable ? 'true' : 'false'); } return $this->printContentItems($contentItems); diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php index 69d68b749dc6..3a920da9cf97 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Doctrine/Property_/JoinColumnTagValueNode.php @@ -119,17 +119,6 @@ public function __toString(): string return $this->printContentItems($contentItems); } - public function changeNullable(bool $nullable): void - { - $this->nullable = $nullable; - } - - public function changeReferencedColumnName(string $referencedColumnName): void - { - $this->orderedVisibleItems[] = 'referencedColumnName'; - $this->referencedColumnName = $referencedColumnName; - } - public function isNullable(): ?bool { return $this->nullable; diff --git a/packages/better-php-doc-parser/src/PhpDocNodeFactory/JMS/JMSInjectPhpDocNodeFactory.php b/packages/better-php-doc-parser/src/PhpDocNodeFactory/JMS/JMSInjectPhpDocNodeFactory.php index 8f34f284aeb7..5ed4fb23fea4 100644 --- a/packages/better-php-doc-parser/src/PhpDocNodeFactory/JMS/JMSInjectPhpDocNodeFactory.php +++ b/packages/better-php-doc-parser/src/PhpDocNodeFactory/JMS/JMSInjectPhpDocNodeFactory.php @@ -11,18 +11,18 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use Rector\BetterPhpDocParser\PhpDocNode\JMS\JMSInjectTagValueNode; use Rector\BetterPhpDocParser\PhpDocNodeFactory\AbstractPhpDocNodeFactory; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; final class JMSInjectPhpDocNodeFactory extends AbstractPhpDocNodeFactory { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NameResolver $nameResolver) + public function __construct(NodeNameResolver $nodeNameResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function getClass(): string @@ -45,7 +45,7 @@ public function createFromNodeAndTokens(Node $node, TokenIterator $tokenIterator return null; } - $serviceName = $inject->value === null ? $this->nameResolver->getName($node) : $inject->value; + $serviceName = $inject->value === null ? $this->nodeNameResolver->getName($node) : $inject->value; // needed for proper doc block formatting $this->resolveContentFromTokenIterator($tokenIterator); diff --git a/packages/better-php-doc-parser/src/PhpDocParser/AnnotationContentResolver.php b/packages/better-php-doc-parser/src/PhpDocParser/AnnotationContentResolver.php index 3ce643f8879c..0a0da54fb19f 100644 --- a/packages/better-php-doc-parser/src/PhpDocParser/AnnotationContentResolver.php +++ b/packages/better-php-doc-parser/src/PhpDocParser/AnnotationContentResolver.php @@ -6,7 +6,6 @@ use Nette\Utils\Strings; use PHPStan\PhpDocParser\Lexer\Lexer; -use PHPStan\PhpDocParser\Parser\ParserException; use PHPStan\PhpDocParser\Parser\TokenIterator; use Rector\BetterPhpDocParser\PhpDocInfo\TokenIteratorFactory; @@ -65,49 +64,45 @@ public function resolveFromTokenIterator(TokenIterator $tokenIterator): string public function resolveNestedKey(string $annotationContent, string $name): string { - try { - $start = false; - $openedCurlyBracketCount = 0; - $tokenContents = []; + $start = false; + $openedCurlyBracketCount = 0; + $tokenContents = []; - $tokenIterator = $this->tokenIteratorFactory->create($annotationContent); + $tokenIterator = $this->tokenIteratorFactory->create($annotationContent); - while (true) { - // the end - if (in_array($tokenIterator->currentTokenType(), [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END], true)) { - break; - } + while (true) { + // the end + if (in_array($tokenIterator->currentTokenType(), [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END], true)) { + break; + } - $start = $this->tryStartWithKey($name, $start, $tokenIterator); - if (! $start) { - $tokenIterator->next(); - continue; - } + $start = $this->tryStartWithKey($name, $start, $tokenIterator); + if (! $start) { + $tokenIterator->next(); + continue; + } - $tokenContents[] = $tokenIterator->currentTokenValue(); + $tokenContents[] = $tokenIterator->currentTokenValue(); - // opening bracket { - if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) { - ++$openedCurlyBracketCount; - } + // opening bracket { + if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) { + ++$openedCurlyBracketCount; + } - // closing bracket } - if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { - --$openedCurlyBracketCount; + // closing bracket } + if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { + --$openedCurlyBracketCount; - // the final one - if ($openedCurlyBracketCount === 0) { - break; - } + // the final one + if ($openedCurlyBracketCount === 0) { + break; } - - $tokenIterator->next(); } - return implode('', $tokenContents); - } catch (ParserException $parserException) { - throw $parserException; + $tokenIterator->next(); } + + return implode('', $tokenContents); } private function cleanMultilineAnnotationContent(string $annotationContent): string diff --git a/packages/better-php-doc-parser/src/PhpDocParser/ClassAnnotationMatcher.php b/packages/better-php-doc-parser/src/PhpDocParser/ClassAnnotationMatcher.php index e460c3bb0e16..12491e7dba49 100644 --- a/packages/better-php-doc-parser/src/PhpDocParser/ClassAnnotationMatcher.php +++ b/packages/better-php-doc-parser/src/PhpDocParser/ClassAnnotationMatcher.php @@ -43,16 +43,7 @@ private function matchFullAnnotationClassWithUses(string $tag, array $uses): ?st continue; } - if ($useUse->alias !== null) { - $unaliasedShortClass = Strings::substring($tag, Strings::length($useUse->alias->toString())); - if (Strings::startsWith($unaliasedShortClass, '\\')) { - return $useUse->name . $unaliasedShortClass; - } - - return $useUse->name . '\\' . $unaliasedShortClass; - } - - return $useUse->name->toString(); + return $this->resolveName($tag, $useUse); } } @@ -66,4 +57,18 @@ private function isUseMatchingName(string $tag, UseUse $useUse): bool return (bool) Strings::match($tag, '#' . $shortNamePattern . '(\\\\[\w]+)?#i'); } + + private function resolveName(string $tag, UseUse $useUse): string + { + if ($useUse->alias === null) { + return $useUse->name->toString(); + } + + $unaliasedShortClass = Strings::substring($tag, Strings::length($useUse->alias->toString())); + if (Strings::startsWith($unaliasedShortClass, '\\')) { + return $useUse->name . $unaliasedShortClass; + } + + return $useUse->name . '\\' . $unaliasedShortClass; + } } diff --git a/packages/cakephp-to-symfony/src/NodeManipulator/DoctrineRepositoryClassMethodManipulator.php b/packages/cakephp-to-symfony/src/NodeManipulator/DoctrineRepositoryClassMethodManipulator.php index a271f05d8d24..a78068bae6fd 100644 --- a/packages/cakephp-to-symfony/src/NodeManipulator/DoctrineRepositoryClassMethodManipulator.php +++ b/packages/cakephp-to-symfony/src/NodeManipulator/DoctrineRepositoryClassMethodManipulator.php @@ -9,7 +9,7 @@ use PhpParser\Node\Stmt\ClassMethod; use Rector\CakePHPToSymfony\Contract\NodeManipulator\RepositoryFindMethodCallManipulatorInterface; use Rector\Core\Exception\NotImplementedException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; @@ -26,9 +26,9 @@ final class DoctrineRepositoryClassMethodManipulator private $callableNodeTraverser; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ValueResolver @@ -40,12 +40,12 @@ final class DoctrineRepositoryClassMethodManipulator */ public function __construct( CallableNodeTraverser $callableNodeTraverser, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ValueResolver $valueResolver, array $repositoryFindMethodCallManipulators ) { $this->callableNodeTraverser = $callableNodeTraverser; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->valueResolver = $valueResolver; $this->repositoryFindMethodCallManipulators = $repositoryFindMethodCallManipulators; } @@ -59,7 +59,7 @@ function (Node $node) use ($entityClass) { return null; } - if (! $this->nameResolver->isName($node->name, 'find')) { + if (! $this->nodeNameResolver->isName($node->name, 'find')) { return null; } diff --git a/packages/cakephp-to-symfony/src/Template/TemplateMethodCallManipulator.php b/packages/cakephp-to-symfony/src/Template/TemplateMethodCallManipulator.php index d3e5f6a27b07..20e86e442e00 100644 --- a/packages/cakephp-to-symfony/src/Template/TemplateMethodCallManipulator.php +++ b/packages/cakephp-to-symfony/src/Template/TemplateMethodCallManipulator.php @@ -12,7 +12,7 @@ use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Return_; use Rector\CakePHPToSymfony\TemplatePathResolver; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; @@ -34,20 +34,20 @@ final class TemplateMethodCallManipulator private $callableNodeTraverser; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; public function __construct( ValueResolver $valueResolver, TemplatePathResolver $templatePathResolver, CallableNodeTraverser $callableNodeTraverser, - NameResolver $nameResolver + NodeNameResolver $nodeNameResolver ) { $this->valueResolver = $valueResolver; $this->templatePathResolver = $templatePathResolver; $this->callableNodeTraverser = $callableNodeTraverser; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function refactorExistingRenderMethodCall(ClassMethod $classMethod): void @@ -121,10 +121,10 @@ private function isThisRenderMethodCall(Node $node): bool return false; } - if (! $this->nameResolver->isName($node->var, 'this')) { + if (! $this->nodeNameResolver->isName($node->var, 'this')) { return false; } - return $this->nameResolver->isName($node->name, 'render'); + return $this->nodeNameResolver->isName($node->name, 'render'); } } diff --git a/packages/code-quality/src/Rector/Identical/SimplifyBoolIdenticalTrueRector.php b/packages/code-quality/src/Rector/Identical/SimplifyBoolIdenticalTrueRector.php index d0d2b7d7e9b9..77233ce225f7 100644 --- a/packages/code-quality/src/Rector/Identical/SimplifyBoolIdenticalTrueRector.php +++ b/packages/code-quality/src/Rector/Identical/SimplifyBoolIdenticalTrueRector.php @@ -75,28 +75,42 @@ public function refactor(Node $node): ?Node private function processBoolTypeToNotBool(Node $node, Expr $leftExpr, Expr $rightExpr): ?Expr { if ($node instanceof Identical) { - if ($this->isTrue($rightExpr)) { - return $leftExpr; - } + return $this->refactorIdentical($leftExpr, $rightExpr); + } - if ($this->isFalse($rightExpr)) { - // prevent !! - if ($leftExpr instanceof BooleanNot) { - return $leftExpr->expr; - } + if ($node instanceof NotIdentical) { + return $this->refactorNotIdentical($leftExpr, $rightExpr); + } - return new BooleanNot($leftExpr); - } + return null; + } + + private function refactorIdentical(Expr $leftExpr, Expr $rightExpr): ?Expr + { + if ($this->isTrue($rightExpr)) { + return $leftExpr; } - if ($node instanceof NotIdentical) { - if ($this->isFalse($rightExpr)) { - return $leftExpr; + if ($this->isFalse($rightExpr)) { + // prevent !! + if ($leftExpr instanceof BooleanNot) { + return $leftExpr->expr; } - if ($this->isTrue($rightExpr)) { - return new BooleanNot($leftExpr); - } + return new BooleanNot($leftExpr); + } + + return null; + } + + private function refactorNotIdentical(Expr $leftExpr, Expr $rightExpr): ?Expr + { + if ($this->isFalse($rightExpr)) { + return $leftExpr; + } + + if ($this->isTrue($rightExpr)) { + return new BooleanNot($leftExpr); } return null; diff --git a/packages/coding-style/src/Imports/UseImportsTraverser.php b/packages/coding-style/src/Imports/UseImportsTraverser.php index cf127044c931..f245ea831c27 100644 --- a/packages/coding-style/src/Imports/UseImportsTraverser.php +++ b/packages/coding-style/src/Imports/UseImportsTraverser.php @@ -8,24 +8,24 @@ use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\GroupUse; use PhpParser\Node\Stmt\Use_; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; final class UseImportsTraverser { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser */ private $callableNodeTraverser; - public function __construct(NameResolver $nameResolver, CallableNodeTraverser $callableNodeTraverser) + public function __construct(NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; } @@ -58,7 +58,7 @@ private function traverseForType(array $stmts, callable $callable, int $desiredT } foreach ($node->uses as $useUse) { - $name = $this->nameResolver->getName($useUse); + $name = $this->nodeNameResolver->getName($useUse); $callable($useUse, $name); } } @@ -84,7 +84,7 @@ private function processGroupUse(GroupUse $groupUse, int $desiredType, callable continue; } - $name = $prefixName . '\\' . $this->nameResolver->getName($useUse); + $name = $prefixName . '\\' . $this->nodeNameResolver->getName($useUse); $callable($useUse, $name); } } diff --git a/packages/coding-style/src/Imports/UsedImportsResolver.php b/packages/coding-style/src/Imports/UsedImportsResolver.php index 27983ae337e7..134b2b71207d 100644 --- a/packages/coding-style/src/Imports/UsedImportsResolver.php +++ b/packages/coding-style/src/Imports/UsedImportsResolver.php @@ -10,7 +10,7 @@ use PhpParser\Node\Stmt\Namespace_; use PhpParser\Node\Stmt\UseUse; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PHPStan\Type\FullyQualifiedObjectType; @@ -22,9 +22,9 @@ final class UsedImportsResolver private $betterNodeFinder; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var UseImportsTraverser @@ -33,11 +33,11 @@ final class UsedImportsResolver public function __construct( BetterNodeFinder $betterNodeFinder, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, UseImportsTraverser $useImportsTraverser ) { $this->betterNodeFinder = $betterNodeFinder; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->useImportsTraverser = $useImportsTraverser; } @@ -67,7 +67,7 @@ public function resolveForStmts(array $stmts): array // add class itself if ($class !== null) { - $className = $this->nameResolver->getName($class); + $className = $this->nodeNameResolver->getName($class); if ($className !== null) { $usedImports[] = new FullyQualifiedObjectType($className); } diff --git a/packages/coding-style/src/Naming/ClassNaming.php b/packages/coding-style/src/Naming/ClassNaming.php index 447258dccf52..c9d42e053dfb 100644 --- a/packages/coding-style/src/Naming/ClassNaming.php +++ b/packages/coding-style/src/Naming/ClassNaming.php @@ -8,18 +8,18 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; final class ClassNaming { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NameResolver $nameResolver) + public function __construct(NodeNameResolver $nodeNameResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -28,7 +28,7 @@ public function __construct(NameResolver $nameResolver) public function getShortName($name): string { if ($name instanceof Name || $name instanceof Identifier) { - $name = $this->nameResolver->getName($name); + $name = $this->nodeNameResolver->getName($name); if ($name === null) { throw new ShouldNotHappenException(); } diff --git a/packages/coding-style/src/Node/NameImporter.php b/packages/coding-style/src/Node/NameImporter.php index 3ff957d0e401..ca7b281e74e0 100644 --- a/packages/coding-style/src/Node/NameImporter.php +++ b/packages/coding-style/src/Node/NameImporter.php @@ -13,7 +13,7 @@ use Rector\CodingStyle\Imports\AliasUsesResolver; use Rector\CodingStyle\Imports\ImportSkipper; use Rector\Core\Configuration\Option; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\StaticTypeMapper; use Rector\PHPStan\Type\FullyQualifiedObjectType; @@ -47,9 +47,9 @@ final class NameImporter private $importSkipper; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ParameterProvider @@ -61,14 +61,14 @@ public function __construct( AliasUsesResolver $aliasUsesResolver, UseAddingCommander $useAddingCommander, ImportSkipper $importSkipper, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ParameterProvider $parameterProvider ) { $this->staticTypeMapper = $staticTypeMapper; $this->aliasUsesResolver = $aliasUsesResolver; $this->useAddingCommander = $useAddingCommander; $this->importSkipper = $importSkipper; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parameterProvider = $parameterProvider; } @@ -111,7 +111,7 @@ private function shouldSkipName(Name $name): bool $importShortClasses = $this->parameterProvider->provideParameter(Option::IMPORT_SHORT_CLASSES_PARAMETER); if (! $importShortClasses) { - $name = $this->nameResolver->getName($name); + $name = $this->nodeNameResolver->getName($name); if ($name !== null && substr_count($name, '\\') === 0) { return true; } diff --git a/packages/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php b/packages/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php index 74365ebb0772..e3720e2830e2 100644 --- a/packages/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php +++ b/packages/coding-style/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php @@ -81,11 +81,12 @@ public function refactor(Node $node): ?Node { $this->reset(); + $hasChanged = false; + if ($node->stmts === null) { return null; } - $hasChanged = false; foreach ($node->stmts as $key => $stmt) { $currentStmtVariableName = null; diff --git a/packages/coding-style/src/Rector/Use_/RemoveUnusedAliasRector.php b/packages/coding-style/src/Rector/Use_/RemoveUnusedAliasRector.php index 6572025cbe23..dcf9eec80714 100644 --- a/packages/coding-style/src/Rector/Use_/RemoveUnusedAliasRector.php +++ b/packages/coding-style/src/Rector/Use_/RemoveUnusedAliasRector.php @@ -49,6 +49,11 @@ final class RemoveUnusedAliasRector extends AbstractRector */ private $shortNameResolver; + /** + * @var string[][] + */ + private $useNamesAliasToName = []; + public function __construct(ShortNameResolver $shortNameResolver) { $this->shortNameResolver = $shortNameResolver; @@ -96,7 +101,7 @@ public function refactor(Node $node): ?Node $this->resolvedNodeNames = []; $this->resolveUsedNameNodes($node); - $useNamesAliasToName = $this->collectUseNamesAliasToName($node); + $this->collectUseNamesAliasToName($node); foreach ($node->uses as $use) { if ($use->alias === null) { @@ -118,16 +123,7 @@ public function refactor(Node $node): ?Node continue; } - // only alias name is used → use last name directly - if (isset($this->resolvedNodeNames[$aliasName])) { - // keep to differentiate 2 aliases classes - if (isset($useNamesAliasToName[$lastName]) && count($useNamesAliasToName[$lastName]) > 1) { - continue; - } - - $this->renameNameNode($this->resolvedNodeNames[$aliasName], $lastName); - $use->alias = null; - } + $this->refactorAliasName($aliasName, $lastName, $use); } return $node; @@ -147,12 +143,9 @@ private function resolveUsedNameNodes(Use_ $node): void $this->resolvedDocPossibleAliases = $this->resolveDocPossibleAliases($searchNode); } - /** - * @return string[][] - */ - private function collectUseNamesAliasToName(Use_ $use): array + private function collectUseNamesAliasToName(Use_ $use): void { - $useNamesAliasToName = []; + $this->useNamesAliasToName = []; $shortNames = $this->shortNameResolver->resolveForNode($use); foreach ($shortNames as $alias => $useImport) { @@ -161,10 +154,8 @@ private function collectUseNamesAliasToName(Use_ $use): array continue; } - $useNamesAliasToName[$shortName][] = $alias; + $this->useNamesAliasToName[$shortName][] = $alias; } - - return $useNamesAliasToName; } private function shouldSkip(string $lastName, string $aliasName): bool @@ -184,81 +175,42 @@ private function shouldSkip(string $lastName, string $aliasName): bool private function renameNameNode(array $usedNameNodes, string $lastName): void { /** @var Identifier|Name $usedName */ + // @todo value objects foreach ($usedNameNodes as [$usedName, $parentNode]) { if ($parentNode instanceof TraitUse) { - foreach ($parentNode->traits as $key => $traitName) { - if (! $this->areNamesEqual($traitName, $usedName)) { - continue; - } - - $parentNode->traits[$key] = new Name($lastName); - } - - continue; + $this->renameTraitUse($lastName, $parentNode, $usedName); } if ($parentNode instanceof Class_) { - if ($parentNode->name !== null && $this->areNamesEqual($parentNode->name, $usedName)) { - $parentNode->name = new Identifier($lastName); - } - - if ($parentNode->extends !== null && $this->areNamesEqual($parentNode->extends, $usedName)) { - $parentNode->extends = new Name($lastName); - } - - foreach ($parentNode->implements as $key => $implementNode) { - if ($this->areNamesEqual($implementNode, $usedName)) { - $parentNode->implements[$key] = new Name($lastName); - } - } - - continue; + $this->renameClass($lastName, $parentNode, $usedName); } if ($parentNode instanceof Param) { - if ($parentNode->type !== null && $this->areNamesEqual($parentNode->type, $usedName)) { - $parentNode->type = new Name($lastName); - } - - continue; + $this->renameParam($lastName, $parentNode, $usedName); } if ($parentNode instanceof New_) { - if ($this->areNamesEqual($parentNode->class, $usedName)) { - $parentNode->class = new Name($lastName); - } - - continue; + $this->renameNew($lastName, $parentNode, $usedName); } if ($parentNode instanceof ClassMethod) { - if ($parentNode->returnType !== null && $this->areNamesEqual($parentNode->returnType, $usedName)) { - $parentNode->returnType = new Name($lastName); - } - - continue; + $this->renameClassMethod($lastName, $parentNode, $usedName); } if ($parentNode instanceof Interface_) { - foreach ($parentNode->extends as $key => $extendInterfaceName) { - if ($this->areNamesEqual($extendInterfaceName, $usedName)) { - $parentNode->extends[$key] = new Name($lastName); - } - } - - continue; + $this->renameInterface($lastName, $parentNode, $usedName); } } } - private function resolveSearchNode(Use_ $node): ?Node + private function resolveSearchNode(Use_ $use): ?Node { - $searchNode = $node->getAttribute(AttributeKey::PARENT_NODE); + $searchNode = $use->getAttribute(AttributeKey::PARENT_NODE); if ($searchNode !== null) { return $searchNode; } - return $node->getAttribute(AttributeKey::NEXT_NODE); + return $use->getAttribute(AttributeKey::NEXT_NODE); } private function resolveUsedNames(Node $searchNode): void @@ -357,4 +309,79 @@ private function appendPossibleAliases(Type $varType, array $possibleDocAliases) } return $possibleDocAliases; } + + private function renameClass(string $lastName, Class_ $class, $usedName): void + { + if ($class->name !== null && $this->areNamesEqual($class->name, $usedName)) { + $class->name = new Identifier($lastName); + } + + if ($class->extends !== null && $this->areNamesEqual($class->extends, $usedName)) { + $class->extends = new Name($lastName); + } + + foreach ($class->implements as $key => $implementNode) { + if ($this->areNamesEqual($implementNode, $usedName)) { + $class->implements[$key] = new Name($lastName); + } + } + } + + private function renameTraitUse(string $lastName, TraitUse $traitUse, $usedName): void + { + foreach ($traitUse->traits as $key => $traitName) { + if (! $this->areNamesEqual($traitName, $usedName)) { + continue; + } + + $traitUse->traits[$key] = new Name($lastName); + } + } + + private function renameParam(string $lastName, $parentNode, $usedName): void + { + if ($parentNode->type !== null && $this->areNamesEqual($parentNode->type, $usedName)) { + $parentNode->type = new Name($lastName); + } + } + + private function renameNew(string $lastName, $parentNode, $usedName): void + { + if ($this->areNamesEqual($parentNode->class, $usedName)) { + $parentNode->class = new Name($lastName); + } + } + + private function renameClassMethod(string $lastName, ClassMethod $classMethod, $usedName): void + { + if ($classMethod->returnType !== null && $this->areNamesEqual($classMethod->returnType, $usedName)) { + $classMethod->returnType = new Name($lastName); + } + } + + private function renameInterface(string $lastName, Interface_ $parentNode, $usedName): void + { + foreach ($parentNode->extends as $key => $extendInterfaceName) { + if ($this->areNamesEqual($extendInterfaceName, $usedName)) { + $parentNode->extends[$key] = new Name($lastName); + } + } + } + + private function refactorAliasName(string $aliasName, string $lastName, UseUse $useUse): void + { + // only alias name is used → use last name directly + + if (! isset($this->resolvedNodeNames[$aliasName])) { + return; + } + + // keep to differentiate 2 aliases classes + if (isset($this->useNamesAliasToName[$lastName]) && count($this->useNamesAliasToName[$lastName]) > 1) { + return; + } + + $this->renameNameNode($this->resolvedNodeNames[$aliasName], $lastName); + $useUse->alias = null; + } } diff --git a/packages/dead-code/src/Doctrine/DoctrineEntityManipulator.php b/packages/dead-code/src/Doctrine/DoctrineEntityManipulator.php index b6c3358c6eda..f172756eeebf 100644 --- a/packages/dead-code/src/Doctrine/DoctrineEntityManipulator.php +++ b/packages/dead-code/src/Doctrine/DoctrineEntityManipulator.php @@ -16,7 +16,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\EntityTagValueNode; use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Class_\InheritanceTypeTagValueNode; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -24,9 +24,9 @@ final class DoctrineEntityManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var DoctrineDocBlockResolver @@ -39,11 +39,11 @@ final class DoctrineEntityManipulator private $nodeTypeResolver; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, DoctrineDocBlockResolver $doctrineDocBlockResolver, NodeTypeResolver $nodeTypeResolver ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->doctrineDocBlockResolver = $doctrineDocBlockResolver; $this->nodeTypeResolver = $nodeTypeResolver; } @@ -123,7 +123,7 @@ public function isMethodCallOnDoctrineEntity(Node $node, string $methodName): bo return false; } - if (! $this->nameResolver->isName($node->name, $methodName)) { + if (! $this->nodeNameResolver->isName($node->name, $methodName)) { return false; } diff --git a/packages/dead-code/src/NodeManipulator/LivingCodeManipulator.php b/packages/dead-code/src/NodeManipulator/LivingCodeManipulator.php new file mode 100644 index 000000000000..bbd6a871a98c --- /dev/null +++ b/packages/dead-code/src/NodeManipulator/LivingCodeManipulator.php @@ -0,0 +1,128 @@ +isNestedExpr($expr)) { + return $this->keepLivingCodeFromExpr($expr->expr); + } + + if ($expr instanceof Variable) { + return $this->keepLivingCodeFromExpr($expr->name); + } + + if ($expr instanceof PropertyFetch) { + return array_merge( + $this->keepLivingCodeFromExpr($expr->var), + $this->keepLivingCodeFromExpr($expr->name) + ); + } + + if ($expr instanceof ArrayDimFetch) { + return array_merge( + $this->keepLivingCodeFromExpr($expr->var), + $this->keepLivingCodeFromExpr($expr->dim) + ); + } + + if ($expr instanceof ClassConstFetch || + $expr instanceof StaticPropertyFetch) { + return array_merge( + $this->keepLivingCodeFromExpr($expr->class), + $this->keepLivingCodeFromExpr($expr->name) + ); + } + + if ($this->isBinaryOpWithoutChange($expr)) { + return array_merge( + $this->keepLivingCodeFromExpr($expr->left), + $this->keepLivingCodeFromExpr($expr->right) + ); + } + + if ($expr instanceof Instanceof_) { + return array_merge( + $this->keepLivingCodeFromExpr($expr->expr), + $this->keepLivingCodeFromExpr($expr->class) + ); + } + + if ($expr instanceof Isset_) { + return array_merge(...array_map(function (Expr $expr): array { + return $this->keepLivingCodeFromExpr($expr); + }, $expr->vars)); + } + + return [$expr]; + } + + private function isBinaryOpWithoutChange($expr): bool + { + return $expr instanceof BinaryOp + && ! ( + $expr instanceof LogicalAnd || + $expr instanceof BooleanAnd || + $expr instanceof LogicalOr || + $expr instanceof BooleanOr || + $expr instanceof Coalesce + ); + } + + private function isNestedExpr($expr): bool + { + return $expr instanceof Cast || + $expr instanceof Empty_ || + $expr instanceof UnaryMinus || + $expr instanceof UnaryPlus || + $expr instanceof BitwiseNot || + $expr instanceof BooleanNot || + $expr instanceof Clone_; + } +} diff --git a/packages/dead-code/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php b/packages/dead-code/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php index 9123baf57dd5..81a664bfda98 100644 --- a/packages/dead-code/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php +++ b/packages/dead-code/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php @@ -22,6 +22,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey; use ReflectionClass; use ReflectionMethod; +use ReflectionParameter; /** * @see \Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\RemoveDelegatingParentCallRectorTest @@ -223,17 +224,8 @@ private function isParentClassMethodVisibilityOrDefaultOverride( /** @var string $methodName */ $methodName = $this->getName($staticCall); $parentClassMethod = $this->functionLikeParsedNodesFinder->findMethod($methodName, $parentClassName); - if ($parentClassMethod !== null) { - if ($parentClassMethod->isProtected() && $classMethod->isPublic()) { - return true; - } - - foreach ($parentClassMethod->params as $key => $parentParam) { - if (! isset($classMethod->params[$key]) && $parentParam->default !== null) { - continue; - } - $this->areNodesEqual($parentParam, $classMethod->params[$key]); - } + if ($parentClassMethod !== null && $parentClassMethod->isProtected() && $classMethod->isPublic()) { + return true; } return $this->checkOverrideUsingReflection($classMethod, $parentClassName, $methodName); @@ -285,17 +277,23 @@ private function areParameterDefaultsDifferent( } return true; } + $methodParam = $classMethod->params[$key]; - if ($parameter->isDefaultValueAvailable() !== isset($methodParam->default)) { - return true; - } - if ($parameter->isDefaultValueAvailable() && $methodParam->default !== null && - ! $this->valueResolver->isValue($methodParam->default, $parameter->getDefaultValue()) - ) { + if ($this->areDefaultValuesDifferent($parameter, $methodParam)) { return true; } } return false; } + + private function areDefaultValuesDifferent(ReflectionParameter $reflectionParameter, Param $methodParam): bool + { + if ($reflectionParameter->isDefaultValueAvailable() !== isset($methodParam->default)) { + return true; + } + + return $reflectionParameter->isDefaultValueAvailable() && $methodParam->default !== null && + ! $this->valueResolver->isValue($methodParam->default, $reflectionParameter->getDefaultValue()); + } } diff --git a/packages/dead-code/src/Rector/Class_/RemoveSetterOnlyPropertyAndMethodCallRector.php b/packages/dead-code/src/Rector/Class_/RemoveSetterOnlyPropertyAndMethodCallRector.php index e4953cda21f0..441d9f649837 100644 --- a/packages/dead-code/src/Rector/Class_/RemoveSetterOnlyPropertyAndMethodCallRector.php +++ b/packages/dead-code/src/Rector/Class_/RemoveSetterOnlyPropertyAndMethodCallRector.php @@ -17,7 +17,7 @@ use Rector\Core\RectorDefinition\CodeSample; use Rector\Core\RectorDefinition\RectorDefinition; use Rector\NodeTypeResolver\Node\AttributeKey; -use Rector\TypeDeclaration\VendorLock\VendorLockResolver; +use Rector\VendorLocker\VendorLockResolver; /** * @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app diff --git a/packages/dead-code/src/Rector/Stmt/RemoveDeadStmtRector.php b/packages/dead-code/src/Rector/Stmt/RemoveDeadStmtRector.php index 324ef10e0982..509f5369116f 100644 --- a/packages/dead-code/src/Rector/Stmt/RemoveDeadStmtRector.php +++ b/packages/dead-code/src/Rector/Stmt/RemoveDeadStmtRector.php @@ -58,7 +58,7 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $livingCode = $this->keepLivingCodeFromExpr($node->expr); + $livingCode = $this->livingCodeManipulator->keepLivingCodeFromExpr($node->expr); if ($livingCode === []) { return $this->removeNodeAndKeepComments($node); } diff --git a/packages/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php b/packages/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php index 72d90655dd25..0b004acdc601 100644 --- a/packages/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php +++ b/packages/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php @@ -8,15 +8,15 @@ use PhpParser\Node\Stmt\Class_; use Rector\Core\NodeContainer\NodeFinder\FunctionLikeParsedNodesFinder; use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use ReflectionMethod; final class ClassUnusedPrivateClassMethodResolver { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ClassManipulator @@ -29,11 +29,11 @@ final class ClassUnusedPrivateClassMethodResolver private $functionLikeParsedNodesFinder; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ClassManipulator $classManipulator, FunctionLikeParsedNodesFinder $functionLikeParsedNodesFinder ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->classManipulator = $classManipulator; $this->functionLikeParsedNodesFinder = $functionLikeParsedNodesFinder; } @@ -44,7 +44,7 @@ public function __construct( public function getClassUnusedMethodNames(Class_ $class): array { /** @var string $className */ - $className = $this->nameResolver->getName($class); + $className = $this->nodeNameResolver->getName($class); $classMethodCalls = $this->functionLikeParsedNodesFinder->findMethodCallsOnClass($className); @@ -98,7 +98,7 @@ private function filterOutSystemMethods(array $unusedMethods): array private function filterOutInterfaceRequiredMethods(Class_ $class, array $unusedMethods): array { /** @var string $className */ - $className = $this->nameResolver->getName($class); + $className = $this->nodeNameResolver->getName($class); $interfaces = class_implements($className); diff --git a/packages/dead-code/src/UnusedNodeResolver/UnusedClassResolver.php b/packages/dead-code/src/UnusedNodeResolver/UnusedClassResolver.php index d5b26e2cadee..dfb4dbe7214e 100644 --- a/packages/dead-code/src/UnusedNodeResolver/UnusedClassResolver.php +++ b/packages/dead-code/src/UnusedNodeResolver/UnusedClassResolver.php @@ -14,7 +14,7 @@ use PhpParser\Node\Stmt\Class_; use Rector\Core\Exception\NotImplementedException; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\Testing\PHPUnit\PHPUnitEnvironment; final class UnusedClassResolver @@ -25,18 +25,18 @@ final class UnusedClassResolver private $cachedUsedClassNames = []; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ParsedNodeCollector */ private $parsedNodeCollector; - public function __construct(NameResolver $nameResolver, ParsedNodeCollector $parsedNodeCollector) + public function __construct(NodeNameResolver $nodeNameResolver, ParsedNodeCollector $parsedNodeCollector) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parsedNodeCollector = $parsedNodeCollector; } @@ -71,15 +71,15 @@ public function isClassWithoutInterfaceAndNotController(Class_ $class): bool return false; } - if ($this->nameResolver->isNames($class, ['*Controller', '*Presenter'])) { + if ($this->nodeNameResolver->isNames($class, ['*Controller', '*Presenter'])) { return false; } - return ! $this->nameResolver->isName($class, '*Test'); + return ! $this->nodeNameResolver->isName($class, '*Test'); } public function isClassUsed(Class_ $class): bool { - return $this->nameResolver->isNames($class, $this->getUsedClassNames()); + return $this->nodeNameResolver->isNames($class, $this->getUsedClassNames()); } /** @@ -106,7 +106,7 @@ private function getParamNodesClassNames(): array if ($paramNode->type instanceof Name) { /** @var string $paramTypeName */ - $paramTypeName = $this->nameResolver->getName($paramNode->type); + $paramTypeName = $this->nodeNameResolver->getName($paramNode->type); $classNames[] = $paramTypeName; } else { throw new NotImplementedException(); @@ -126,7 +126,7 @@ private function getNewNodesClassNames(): array /** @var New_[] $newNodes */ $newNodes = $this->parsedNodeCollector->getNodesByType(New_::class); foreach ($newNodes as $newNode) { - $newNodeClassName = $this->nameResolver->getName($newNode->class); + $newNodeClassName = $this->nodeNameResolver->getName($newNode->class); if (! is_string($newNodeClassName)) { continue; } @@ -147,7 +147,7 @@ private function getStaticCallClassNames(): array /** @var StaticCall[] $staticCallNodes */ $staticCallNodes = $this->parsedNodeCollector->getNodesByType(StaticCall::class); foreach ($staticCallNodes as $staticCallNode) { - $staticClassName = $this->nameResolver->getName($staticCallNode->class); + $staticClassName = $this->nodeNameResolver->getName($staticCallNode->class); if (! is_string($staticClassName)) { continue; } @@ -167,7 +167,7 @@ private function getClassConstantFetchNames(): array $classNames = []; foreach ($classConstFetches as $classConstFetch) { - $className = $this->nameResolver->getName($classConstFetch->class); + $className = $this->nodeNameResolver->getName($classConstFetch->class); if (! is_string($className)) { continue; } diff --git a/packages/doctrine/src/Provider/EntityWithMissingUuidProvider.php b/packages/doctrine/src/Provider/EntityWithMissingUuidProvider.php index 89e1df334ed3..85e4bd62db6c 100644 --- a/packages/doctrine/src/Provider/EntityWithMissingUuidProvider.php +++ b/packages/doctrine/src/Provider/EntityWithMissingUuidProvider.php @@ -12,7 +12,7 @@ use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\IdTagValueNode; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -39,20 +39,20 @@ final class EntityWithMissingUuidProvider private $classManipulator; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; public function __construct( ParsedNodeCollector $parsedNodeCollector, DoctrineDocBlockResolver $doctrineDocBlockResolver, ClassManipulator $classManipulator, - NameResolver $nameResolver + NodeNameResolver $nodeNameResolver ) { $this->parsedNodeCollector = $parsedNodeCollector; $this->doctrineDocBlockResolver = $doctrineDocBlockResolver; $this->classManipulator = $classManipulator; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -94,7 +94,7 @@ private function hasClassIdPropertyWithUuidType(Class_ $class): bool continue; } - if (! $this->nameResolver->isName($classStmt, 'id')) { + if (! $this->nodeNameResolver->isName($classStmt, 'id')) { continue; } diff --git a/packages/laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php b/packages/laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php index be4a594bebc3..80cc915e5527 100644 --- a/packages/laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php +++ b/packages/laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php @@ -7,6 +7,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Exception\ShouldNotHappenException; @@ -125,13 +126,7 @@ public function refactor(Node $node): ?Node } if ($functionChange instanceof ArrayFunctionToMethodCall) { - if ($functionChange->getArrayMethod() && $this->isArrayType($node->args[0]->value)) { - return new MethodCall($propertyFetchNode, $functionChange->getArrayMethod(), $node->args); - } - - if ($functionChange->getNonArrayMethod() && ! $this->isArrayType($node->args[0]->value)) { - return new MethodCall($propertyFetchNode, $functionChange->getNonArrayMethod(), $node->args); - } + return $this->createMethodCallArrayFunctionToMethodCall($node, $functionChange, $propertyFetchNode); } throw new ShouldNotHappenException(); @@ -169,4 +164,20 @@ private function isFunctionToMethodCallWithArgs(Node $node, $functionChange): bo return count($node->args) >= 1; } + + private function createMethodCallArrayFunctionToMethodCall( + FuncCall $funcCall, + ArrayFunctionToMethodCall $arrayFunctionToMethodCall, + PropertyFetch $propertyFetch + ) { + if ($arrayFunctionToMethodCall->getArrayMethod() && $this->isArrayType($funcCall->args[0]->value)) { + return new MethodCall($propertyFetch, $arrayFunctionToMethodCall->getArrayMethod(), $funcCall->args); + } + + if ($arrayFunctionToMethodCall->getNonArrayMethod() && ! $this->isArrayType($funcCall->args[0]->value)) { + return new MethodCall($propertyFetch, $arrayFunctionToMethodCall->getNonArrayMethod(), $funcCall->args); + } + + return null; + } } diff --git a/packages/legacy/src/Rector/ClassMethod/ChangeSingletonToServiceRector.php b/packages/legacy/src/Rector/ClassMethod/ChangeSingletonToServiceRector.php index 8e40bcd3621c..593611e1c9e1 100644 --- a/packages/legacy/src/Rector/ClassMethod/ChangeSingletonToServiceRector.php +++ b/packages/legacy/src/Rector/ClassMethod/ChangeSingletonToServiceRector.php @@ -128,24 +128,31 @@ private function refactorClassStmts( continue; } - if (! $property->isPublic()) { - // remove non-public empty - if ($property->stmts === []) { - $this->removeNodeFromStatements($node, $property); - } else { - $this->makePublic($property); - } + if ($property->isPublic()) { + continue; + } + + // remove non-public empty + if ($property->stmts === []) { + $this->removeNodeFromStatements($node, $property); + } else { + $this->makePublic($property); } } - foreach ($node->getProperties() as $property) { - if (! $this->isName($property, $singletonPropertyName)) { + $this->removePropertyByName($node, $singletonPropertyName); + + return $node; + } + + private function removePropertyByName(Class_ $class, string $propertyName): void + { + foreach ($class->getProperties() as $property) { + if (! $this->isName($property, $propertyName)) { continue; } - $this->removeNodeFromStatements($node, $property); + $this->removeNodeFromStatements($class, $property); } - - return $node; } } diff --git a/packages/minimal-scope/src/Rector/Class_/ChangeLocalPropertyToVariableRector.php b/packages/minimal-scope/src/Rector/Class_/ChangeLocalPropertyToVariableRector.php index 4ca2a4c5bc77..daa5fc0dcdae 100644 --- a/packages/minimal-scope/src/Rector/Class_/ChangeLocalPropertyToVariableRector.php +++ b/packages/minimal-scope/src/Rector/Class_/ChangeLocalPropertyToVariableRector.php @@ -221,42 +221,10 @@ private function isPropertyChangingInMultipleMethodCalls( } if ($node instanceof If_) { - $this->traverseNodesWithCallable($node->cond, function (Node $node) use ( - $privatePropertyName, - &$isPropertyReadInIf - ) { - if (! $this->propertyFetchManipulator->isLocalPropertyOfNames($node, [$privatePropertyName])) { - return null; - } - - $isPropertyReadInIf = true; - - return NodeTraverser::STOP_TRAVERSAL; - }); + $isPropertyReadInIf = $this->refactorIf($node, $privatePropertyName); } - // here cannot be any property assign - $this->traverseNodesWithCallable($node, function (Node $node) use ( - &$isPropertyChanging, - $privatePropertyName - ) { - if (! $node instanceof Assign) { - return null; - } - - if (! $node->var instanceof PropertyFetch) { - return null; - } - - if (! $this->isName($node->var->name, $privatePropertyName)) { - return null; - } - - $isPropertyChanging = true; - - return NodeTraverser::STOP_TRAVERSAL; - }); - + $isPropertyChanging = $this->isPropertyChanging($node, $this, $privatePropertyName); if (! $isPropertyChanging) { return null; } @@ -279,4 +247,52 @@ private function isScopeChangingNode(Node $node): bool return false; } + + /** + * @return bool|null + */ + private function refactorIf(If_ $if, string $privatePropertyName) + { + $this->traverseNodesWithCallable($if->cond, function (Node $node) use ( + $privatePropertyName, + &$isPropertyReadInIf + ) { + if (! $this->propertyFetchManipulator->isLocalPropertyOfNames($node, [$privatePropertyName])) { + return null; + } + + $isPropertyReadInIf = true; + + return NodeTraverser::STOP_TRAVERSAL; + }); + + return $isPropertyReadInIf; + } + + private function isPropertyChanging(Node $node, self $this__, string $privatePropertyName): bool + { + $isPropertyChanging = false; + // here cannot be any property assign + $this__->traverseNodesWithCallable($node, function (Node $node) use ( + &$isPropertyChanging, + $privatePropertyName + ) { + if (! $node instanceof Assign) { + return null; + } + + if (! $node->var instanceof PropertyFetch) { + return null; + } + + if (! $this->isName($node->var->name, $privatePropertyName)) { + return null; + } + + $isPropertyChanging = true; + + return NodeTraverser::STOP_TRAVERSAL; + }); + return $isPropertyChanging; + } } diff --git a/packages/nette-tester-to-phpunit/src/AssertManipulator.php b/packages/nette-tester-to-phpunit/src/AssertManipulator.php index 7dc0976f2ac1..41e2d17d4a4c 100644 --- a/packages/nette-tester-to-phpunit/src/AssertManipulator.php +++ b/packages/nette-tester-to-phpunit/src/AssertManipulator.php @@ -20,7 +20,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Core\PhpParser\Node\Commander\NodeAddingCommander; use Rector\Core\PhpParser\Node\Commander\NodeRemovingCommander; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -50,9 +50,9 @@ final class AssertManipulator ]; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver @@ -80,14 +80,14 @@ final class AssertManipulator private $stringTypeAnalyzer; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, ValueResolver $valueResolver, NodeAddingCommander $nodeAddingCommander, NodeRemovingCommander $nodeRemovingCommander, StringTypeAnalyzer $stringTypeAnalyzer ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; $this->valueResolver = $valueResolver; $this->nodeAddingCommander = $nodeAddingCommander; @@ -100,23 +100,20 @@ public function __construct( */ public function processStaticCall(StaticCall $staticCall): Node { - if ($this->nameResolver->isNames($staticCall, ['contains', 'notContains'])) { + if ($this->nodeNameResolver->isNames($staticCall, ['truthy', 'falsey'])) { + return $this->processTruthyOrFalseyCall($staticCall); + } + + if ($this->nodeNameResolver->isNames($staticCall, ['contains', 'notContains'])) { $this->processContainsCall($staticCall); - } elseif ($this->nameResolver->isNames($staticCall, ['exception', 'throws'])) { + } elseif ($this->nodeNameResolver->isNames($staticCall, ['exception', 'throws'])) { $this->processExceptionCall($staticCall); - } elseif ($this->nameResolver->isName($staticCall, 'type')) { + } elseif ($this->nodeNameResolver->isName($staticCall, 'type')) { $this->processTypeCall($staticCall); - } elseif ($this->nameResolver->isName($staticCall, 'noError')) { + } elseif ($this->nodeNameResolver->isName($staticCall, 'noError')) { $this->processNoErrorCall($staticCall); - } elseif ($this->nameResolver->isNames($staticCall, ['truthy', 'falsey'])) { - return $this->processTruthyOrFalseyCall($staticCall); } else { - foreach ($this->assertMethodsRemap as $oldMethod => $newMethod) { - if ($this->nameResolver->isName($staticCall, $oldMethod)) { - $staticCall->name = new Identifier($newMethod); - continue; - } - } + $this->renameAssertMethod($staticCall); } // self or class, depending on the context @@ -138,12 +135,12 @@ public function processStaticCall(StaticCall $staticCall): Node private function processContainsCall(StaticCall $staticCall): void { if ($this->stringTypeAnalyzer->isStringOrUnionStringOnlyType($staticCall->args[1]->value)) { - $name = $this->nameResolver->isName( + $name = $this->nodeNameResolver->isName( $staticCall, 'contains' ) ? 'assertStringContainsString' : 'assertStringNotContainsString'; } else { - $name = $this->nameResolver->isName($staticCall, 'contains') ? 'assertContains' : 'assertNotContains'; + $name = $this->nodeNameResolver->isName($staticCall, 'contains') ? 'assertContains' : 'assertNotContains'; } $staticCall->name = new Identifier($name); @@ -165,30 +162,12 @@ private function processExceptionCall(StaticCall $staticCall): void // expect message if (isset($staticCall->args[2])) { - $method = 'expectExceptionMessage'; - - if ($this->sholdBeStaticCall($staticCall)) { - $expectExceptionMessage = new StaticCall(new Name('self'), $method); - } else { - $expectExceptionMessage = new MethodCall(new Variable('this'), $method); - } - - $expectExceptionMessage->args[] = $staticCall->args[2]; - $this->nodeAddingCommander->addNodeAfterNode($expectExceptionMessage, $staticCall); + $this->refactorExpectException($staticCall); } // expect code if (isset($staticCall->args[3])) { - $method = 'expectExceptionCode'; - - if ($this->sholdBeStaticCall($staticCall)) { - $expectExceptionCode = new StaticCall(new Name('self'), $method); - } else { - $expectExceptionCode = new MethodCall(new Variable('this'), $method); - } - - $expectExceptionCode->args[] = $staticCall->args[3]; - $this->nodeAddingCommander->addNodeAfterNode($expectExceptionCode, $staticCall); + $this->refactorExpectExceptionCode($staticCall); } /** @var Closure $closure */ @@ -258,7 +237,7 @@ private function processNoErrorCall(StaticCall $staticCall): void */ private function processTruthyOrFalseyCall(StaticCall $staticCall): Expr { - $method = $this->nameResolver->isName($staticCall, 'truthy') ? 'assertTrue' : 'assertFalse'; + $method = $this->nodeNameResolver->isName($staticCall, 'truthy') ? 'assertTrue' : 'assertFalse'; if (! $this->sholdBeStaticCall($staticCall)) { $call = new MethodCall(new Variable('this'), $method); @@ -281,4 +260,44 @@ private function sholdBeStaticCall(StaticCall $staticCall): bool { return ! (bool) $staticCall->getAttribute(AttributeKey::CLASS_NODE); } + + private function refactorExpectException(StaticCall $staticCall): string + { + $method = 'expectExceptionMessage'; + + if ($this->sholdBeStaticCall($staticCall)) { + $expectExceptionMessage = new StaticCall(new Name('self'), $method); + } else { + $expectExceptionMessage = new MethodCall(new Variable('this'), $method); + } + + $expectExceptionMessage->args[] = $staticCall->args[2]; + $this->nodeAddingCommander->addNodeAfterNode($expectExceptionMessage, $staticCall); + return $method; + } + + private function refactorExpectExceptionCode(StaticCall $staticCall): void + { + $method = 'expectExceptionCode'; + + if ($this->sholdBeStaticCall($staticCall)) { + $expectExceptionCode = new StaticCall(new Name('self'), $method); + } else { + $expectExceptionCode = new MethodCall(new Variable('this'), $method); + } + + $expectExceptionCode->args[] = $staticCall->args[3]; + $this->nodeAddingCommander->addNodeAfterNode($expectExceptionCode, $staticCall); + } + + private function renameAssertMethod(StaticCall $staticCall): void + { + foreach ($this->assertMethodsRemap as $oldMethod => $newMethod) { + if (! $this->nodeNameResolver->isName($staticCall, $oldMethod)) { + continue; + } + + $staticCall->name = new Identifier($newMethod); + } + } } diff --git a/packages/nette-to-symfony/src/Route/RouteInfoFactory.php b/packages/nette-to-symfony/src/Route/RouteInfoFactory.php index 31ac548443b1..c7e757fbb317 100644 --- a/packages/nette-to-symfony/src/Route/RouteInfoFactory.php +++ b/packages/nette-to-symfony/src/Route/RouteInfoFactory.php @@ -11,16 +11,16 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Scalar\String_; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\NetteToSymfony\ValueObject\RouteInfo; final class RouteInfoFactory { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ValueResolver @@ -33,11 +33,11 @@ final class RouteInfoFactory private $parsedNodeCollector; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ValueResolver $valueResolver, ParsedNodeCollector $parsedNodeCollector ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->valueResolver = $valueResolver; $this->parsedNodeCollector = $parsedNodeCollector; } @@ -58,12 +58,12 @@ public function createFromNode(Node $node): ?RouteInfo return null; } - if (! $this->nameResolver->isNames($node, ['get', 'head', 'post', 'put', 'patch', 'delete'])) { + if (! $this->nodeNameResolver->isNames($node, ['get', 'head', 'post', 'put', 'patch', 'delete'])) { return null; } /** @var string $methodName */ - $methodName = $this->nameResolver->getName($node); + $methodName = $this->nodeNameResolver->getName($node); $uppercasedMethodName = strtoupper($methodName); $methods = []; @@ -95,72 +95,88 @@ private function createRouteInfoFromArgs(Node $node, array $methods = []): ?Rout $targetNode = $node->args[1]->value; if ($targetNode instanceof ClassConstFetch) { - /** @var ClassConstFetch $controllerMethodNode */ - $controllerMethodNode = $node->args[1]->value; - - // SomePresenter::class - if ($this->nameResolver->isName($controllerMethodNode->name, 'class')) { - $presenterClass = $this->nameResolver->getName($controllerMethodNode->class); - if ($presenterClass === null) { - return null; - } - - if (! class_exists($presenterClass)) { - return null; - } - - if (method_exists($presenterClass, 'run')) { - return new RouteInfo($presenterClass, 'run', $routePath, null, $methods); - } - } + return $this->createForClassConstFetch($node, $methods, $routePath); // @todo method specific route } if ($targetNode instanceof String_) { - $targetValue = $targetNode->value; - if (! Strings::contains($targetValue, ':')) { - return null; - } + return $this->createForString($targetNode, $routePath); + } - [$controller, $method] = explode(':', $targetValue); + return null; + } - // detect class by controller name? - // foreach all instance and try to match a name $controller . 'Presenter/Controller' + private function normalizeArgumentWrappers(string $routePath): string + { + return str_replace(['<', '>'], ['{', '}'], $routePath); + } - $classNode = $this->parsedNodeCollector->findByShortName($controller . 'Presenter'); - if ($classNode === null) { - $classNode = $this->parsedNodeCollector->findByShortName($controller . 'Controller'); - } + /** + * @param New_|StaticCall $node + * @param string[] $methods + */ + private function createForClassConstFetch(Node $node, array $methods, string $routePath): ?RouteInfo + { + /** @var ClassConstFetch $controllerMethodNode */ + $controllerMethodNode = $node->args[1]->value; - // unable to find here - if ($classNode === null) { + // SomePresenter::class + if ($this->nodeNameResolver->isName($controllerMethodNode->name, 'class')) { + $presenterClass = $this->nodeNameResolver->getName($controllerMethodNode->class); + if ($presenterClass === null) { return null; } - $controllerClass = $this->nameResolver->getName($classNode); - if ($controllerClass === null) { + if (! class_exists($presenterClass)) { return null; } - $methodName = null; - if (method_exists($controllerClass, 'render' . ucfirst($method))) { - $methodName = 'render' . ucfirst($method); - } elseif (method_exists($controllerClass, 'action' . ucfirst($method))) { - $methodName = 'action' . ucfirst($method); + if (method_exists($presenterClass, 'run')) { + return new RouteInfo($presenterClass, 'run', $routePath, null, $methods); } - - if ($methodName === null) { - return null; - } - - return new RouteInfo($controllerClass, $methodName, $routePath, null, []); } return null; } - private function normalizeArgumentWrappers(string $routePath): string + private function createForString(String_ $string, string $routePath): ?RouteInfo { - return str_replace(['<', '>'], ['{', '}'], $routePath); + $targetValue = $string->value; + if (! Strings::contains($targetValue, ':')) { + return null; + } + + [$controller, $method] = explode(':', $targetValue); + + // detect class by controller name? + // foreach all instance and try to match a name $controller . 'Presenter/Controller' + + $classNode = $this->parsedNodeCollector->findByShortName($controller . 'Presenter'); + if ($classNode === null) { + $classNode = $this->parsedNodeCollector->findByShortName($controller . 'Controller'); + } + + // unable to find here + if ($classNode === null) { + return null; + } + + $controllerClass = $this->nodeNameResolver->getName($classNode); + if ($controllerClass === null) { + return null; + } + + $methodName = null; + if (method_exists($controllerClass, 'render' . ucfirst($method))) { + $methodName = 'render' . ucfirst($method); + } elseif (method_exists($controllerClass, 'action' . ucfirst($method))) { + $methodName = 'action' . ucfirst($method); + } + + if ($methodName === null) { + return null; + } + + return new RouteInfo($controllerClass, $methodName, $routePath, null, []); } } diff --git a/packages/nette-to-symfony/src/SymfonyFormAbstractTypeFactory.php b/packages/nette-to-symfony/src/SymfonyFormAbstractTypeFactory.php index c60e6da7bfba..96c5c3c0987f 100644 --- a/packages/nette-to-symfony/src/SymfonyFormAbstractTypeFactory.php +++ b/packages/nette-to-symfony/src/SymfonyFormAbstractTypeFactory.php @@ -16,7 +16,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Expression; use Rector\Core\PhpParser\Node\NodeFactory; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Symfony\Component\Form\Extension\Core\Type\TextType; final class SymfonyFormAbstractTypeFactory @@ -27,14 +27,14 @@ final class SymfonyFormAbstractTypeFactory private $nodeFactory; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NodeFactory $nodeFactory, NameResolver $nameResolver) + public function __construct(NodeFactory $nodeFactory, NodeNameResolver $nodeNameResolver) { $this->nodeFactory = $nodeFactory; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -69,7 +69,7 @@ private function createBuildFormMethodCalls(array $methodCalls, Variable $formBu // create symfony form from nette form method calls foreach ($methodCalls as $methodCall) { - if ($this->nameResolver->isName($methodCall->name, 'addText')) { + if ($this->nodeNameResolver->isName($methodCall->name, 'addText')) { $optionsArray = $this->createOptionsArray($methodCall); $formTypeClassConstant = $this->nodeFactory->createClassConstantReference(TextType::class); diff --git a/packages/nette/src/TemplatePropertyAssignCollector.php b/packages/nette/src/TemplatePropertyAssignCollector.php index 827183522a16..485cad23fd05 100644 --- a/packages/nette/src/TemplatePropertyAssignCollector.php +++ b/packages/nette/src/TemplatePropertyAssignCollector.php @@ -11,7 +11,7 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\ClassMethod; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\Nette\ValueObject\MagicTemplatePropertyCalls; @@ -38,14 +38,14 @@ final class TemplatePropertyAssignCollector private $callableNodeTraverser; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(CallableNodeTraverser $callableNodeTraverser, NameResolver $nameResolver) + public function __construct(CallableNodeTraverser $callableNodeTraverser, NodeNameResolver $nodeNameResolver) { $this->callableNodeTraverser = $callableNodeTraverser; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function collectTemplateFileNameVariablesAndNodesToRemove( @@ -73,7 +73,7 @@ function (Node $node): void { private function collectTemplateFileExpr(MethodCall $methodCall): void { - if ($this->nameResolver->isName($methodCall->name, 'render')) { + if ($this->nodeNameResolver->isName($methodCall->name, 'render')) { if (isset($methodCall->args[0])) { $this->templateFileExpr = $methodCall->args[0]->value; } @@ -81,7 +81,7 @@ private function collectTemplateFileExpr(MethodCall $methodCall): void $this->nodesToRemove[] = $methodCall; } - if ($this->nameResolver->isName($methodCall->name, 'setFile')) { + if ($this->nodeNameResolver->isName($methodCall->name, 'setFile')) { $this->templateFileExpr = $methodCall->args[0]->value; $this->nodesToRemove[] = $methodCall; } @@ -91,11 +91,11 @@ private function collectVariableFromAssign(Assign $assign): void { // $this->template = x if ($assign->var instanceof PropertyFetch) { - if (! $this->nameResolver->isName($assign->var->var, 'template')) { + if (! $this->nodeNameResolver->isName($assign->var->var, 'template')) { return; } - $variableName = $this->nameResolver->getName($assign->var); + $variableName = $this->nodeNameResolver->getName($assign->var); $this->templateVariables[$variableName] = $assign->expr; $this->nodesToRemove[] = $assign; @@ -121,10 +121,10 @@ private function isTemplatePropertyFetch(Expr $expr): bool return false; } - if (! $this->nameResolver->isName($expr->var, 'this')) { + if (! $this->nodeNameResolver->isName($expr->var, 'this')) { return false; } - return $this->nameResolver->isName($expr->name, 'template'); + return $this->nodeNameResolver->isName($expr->name, 'template'); } } diff --git a/packages/node-type-resolver/src/NodeTypeCorrector/PregMatchTypeCorrector.php b/packages/node-type-resolver/src/NodeTypeCorrector/PregMatchTypeCorrector.php index d567dc1b3720..acc3b15ce4b1 100644 --- a/packages/node-type-resolver/src/NodeTypeCorrector/PregMatchTypeCorrector.php +++ b/packages/node-type-resolver/src/NodeTypeCorrector/PregMatchTypeCorrector.php @@ -12,7 +12,7 @@ use PHPStan\Type\MixedType; use PHPStan\Type\Type; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -24,9 +24,9 @@ final class PregMatchTypeCorrector private $betterNodeFinder; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BetterStandardPrinter @@ -35,11 +35,11 @@ final class PregMatchTypeCorrector public function __construct( BetterNodeFinder $betterNodeFinder, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, BetterStandardPrinter $betterStandardPrinter ) { $this->betterNodeFinder = $betterNodeFinder; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->betterStandardPrinter = $betterStandardPrinter; } @@ -69,7 +69,7 @@ public function correct(Node $node, Type $originalType): Type continue; } - if (! $this->nameResolver->isNames($funcCallNode, ['preg_match', 'preg_match_all'])) { + if (! $this->nodeNameResolver->isNames($funcCallNode, ['preg_match', 'preg_match_all'])) { continue; } diff --git a/packages/node-type-resolver/src/NodeTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver.php index f2edafbfe400..3823ca600ec0 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver.php @@ -32,7 +32,7 @@ use Rector\BetterPhpDocParser\PhpDocParser\BetterPhpDocParser; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory; @@ -49,9 +49,9 @@ final class NodeTypeResolver private $perNodeTypeResolvers = []; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ClassReflectionTypesResolver @@ -98,7 +98,7 @@ final class NodeTypeResolver */ public function __construct( BetterPhpDocParser $betterPhpDocParser, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ParsedNodeCollector $parsedNodeCollector, ClassReflectionTypesResolver $classReflectionTypesResolver, ReflectionProvider $reflectionProvider, @@ -107,7 +107,7 @@ public function __construct( ObjectTypeSpecifier $objectTypeSpecifier, array $perNodeTypeResolvers ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; foreach ($perNodeTypeResolvers as $perNodeTypeResolver) { $this->addPerNodeTypeResolver($perNodeTypeResolver); @@ -162,15 +162,7 @@ public function isObjectType(Node $node, $requiredType): bool return true; } - if ($resolvedType instanceof UnionType) { - foreach ($resolvedType->getTypes() as $unionedType) { - if ($unionedType->equals($requiredType)) { - return true; - } - } - } - - return false; + return $this->isMatchingUnionType($requiredType, $resolvedType); } public function resolve(Node $node): Type @@ -231,11 +223,7 @@ public function getStaticType(Node $node): Type } if ($node instanceof PropertyFetch) { - // compensate 3rd party non-analysed property reflection - $vendorPropertyType = $this->getVendorPropertyFetchType($node); - if ($vendorPropertyType !== null) { - return $vendorPropertyType; - } + return $this->resolvePropertyFetchType($node); } return $this->objectTypeSpecifier->narrowToFullyQualifiedOrAlaisedObjectType($node, $staticType); @@ -369,11 +357,7 @@ private function resolveFirstType(Node $node): Type /** @var Scope|null $nodeScope */ $nodeScope = $node->getAttribute(AttributeKey::SCOPE); - if ($nodeScope === null) { - return new MixedType(); - } - - if (! $node instanceof Expr) { + if ($nodeScope === null || ! $node instanceof Expr) { return new MixedType(); } @@ -443,7 +427,7 @@ private function isAnonymousClass(Node $node): bool return false; } - $className = $this->nameResolver->getName($node); + $className = $this->nodeNameResolver->getName($node); return $className === null || Strings::contains($className, 'AnonymousClass'); } @@ -460,7 +444,7 @@ private function getVendorPropertyFetchType(PropertyFetch $propertyFetch): ?Type } // 3rd party code - $propertyName = $this->nameResolver->getName($propertyFetch->name); + $propertyName = $this->nodeNameResolver->getName($propertyFetch->name); if ($propertyName === null) { return null; } @@ -500,4 +484,30 @@ private function getClassLikeTypesByClassName(string $className): array return array_unique($classLikeTypes); } + + private function isMatchingUnionType(Type $requiredType, Type $resolvedType): bool + { + if (! $resolvedType instanceof UnionType) { + return false; + } + foreach ($resolvedType->getTypes() as $unionedType) { + if (! $unionedType->equals($requiredType)) { + continue; + } + return true; + } + + return false; + } + + private function resolvePropertyFetchType(PropertyFetch $propertyFetch) + { + // compensate 3rd party non-analysed property reflection + $vendorPropertyType = $this->getVendorPropertyFetchType($propertyFetch); + if ($vendorPropertyType !== null) { + return $vendorPropertyType; + } + + return new MixedType(); + } } diff --git a/packages/node-type-resolver/src/PHPStan/Type/StaticTypeAnalyzer.php b/packages/node-type-resolver/src/PHPStan/Type/StaticTypeAnalyzer.php index e5f599bb2783..75594dcecc74 100644 --- a/packages/node-type-resolver/src/PHPStan/Type/StaticTypeAnalyzer.php +++ b/packages/node-type-resolver/src/PHPStan/Type/StaticTypeAnalyzer.php @@ -50,17 +50,7 @@ public function isAlwaysTruableType(Type $type): bool return false; } - if ($type instanceof UnionType) { - foreach ($type->getTypes() as $unionedType) { - if (! $this->isAlwaysTruableType($unionedType)) { - return false; - } - } - - return true; - } - - return true; + return $this->isAlwaysTruableUnionType($type); } public function isNullable(Type $type): bool @@ -86,4 +76,19 @@ private function isScalarType(Type $type): bool return $type instanceof BooleanType || $type instanceof StringType || $type instanceof IntegerType || $type instanceof FloatType; } + + private function isAlwaysTruableUnionType(Type $type): bool + { + if (! $type instanceof UnionType) { + return false; + } + + foreach ($type->getTypes() as $unionedType) { + if (! $this->isAlwaysTruableType($unionedType)) { + return false; + } + } + + return true; + } } diff --git a/packages/node-type-resolver/src/PerNodeTypeResolver/ParamTypeResolver.php b/packages/node-type-resolver/src/PerNodeTypeResolver/ParamTypeResolver.php index 86ad6b05905a..e9df4f6e8631 100644 --- a/packages/node-type-resolver/src/PerNodeTypeResolver/ParamTypeResolver.php +++ b/packages/node-type-resolver/src/PerNodeTypeResolver/ParamTypeResolver.php @@ -14,7 +14,7 @@ use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -26,9 +26,9 @@ final class ParamTypeResolver implements PerNodeTypeResolverInterface { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser @@ -40,9 +40,9 @@ final class ParamTypeResolver implements PerNodeTypeResolverInterface */ private $nodeTypeResolver; - public function __construct(NameResolver $nameResolver, CallableNodeTraverser $callableNodeTraverser) + public function __construct(NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; } @@ -83,7 +83,7 @@ public function resolve(Node $node): Type private function resolveFromType(Node $node) { if ($node->type !== null && ! $node->type instanceof Identifier) { - $resolveTypeName = $this->nameResolver->getName($node->type); + $resolveTypeName = $this->nodeNameResolver->getName($node->type); if ($resolveTypeName) { // @todo map the other way every type :) return new ObjectType($resolveTypeName); @@ -101,7 +101,7 @@ private function resolveFromFirstVariableUse(Param $param): Type } /** @var string $paramName */ - $paramName = $this->nameResolver->getName($param); + $paramName = $this->nodeNameResolver->getName($param); $paramStaticType = new MixedType(); // special case for param inside method/function @@ -112,7 +112,7 @@ function (Node $node) use ($paramName, &$paramStaticType): ?int { return null; } - if (! $this->nameResolver->isName($node, $paramName)) { + if (! $this->nodeNameResolver->isName($node, $paramName)) { return null; } @@ -131,7 +131,7 @@ private function resolveFromFunctionDocBlock(Param $param): Type $parentNode = $param->getAttribute(AttributeKey::PARENT_NODE); /** @var string $paramName */ - $paramName = $this->nameResolver->getName($param); + $paramName = $this->nodeNameResolver->getName($param); /** @var PhpDocInfo $phpDocInfo */ $phpDocInfo = $parentNode->getAttribute(AttributeKey::PHP_DOC_INFO); diff --git a/packages/node-type-resolver/src/PerNodeTypeResolver/StaticCallTypeResolver.php b/packages/node-type-resolver/src/PerNodeTypeResolver/StaticCallTypeResolver.php index a767d555326a..b2f076416cab 100644 --- a/packages/node-type-resolver/src/PerNodeTypeResolver/StaticCallTypeResolver.php +++ b/packages/node-type-resolver/src/PerNodeTypeResolver/StaticCallTypeResolver.php @@ -9,7 +9,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Type\Type; use PHPStan\Type\TypeUtils; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -22,13 +22,13 @@ final class StaticCallTypeResolver implements PerNodeTypeResolverInterface private $nodeTypeResolver; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NameResolver $nameResolver) + public function __construct(NodeNameResolver $nodeNameResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -53,7 +53,7 @@ public function getNodeClasses(): array public function resolve(Node $node): Type { $classType = $this->nodeTypeResolver->resolve($node->class); - $methodName = $this->nameResolver->getName($node->name); + $methodName = $this->nodeNameResolver->getName($node->name); // no specific method found, return class types, e.g. ::$method() if (! is_string($methodName)) { diff --git a/packages/node-type-resolver/src/PerNodeTypeResolver/VariableTypeResolver.php b/packages/node-type-resolver/src/PerNodeTypeResolver/VariableTypeResolver.php index 2b1b9a66c4e8..520835682d53 100644 --- a/packages/node-type-resolver/src/PerNodeTypeResolver/VariableTypeResolver.php +++ b/packages/node-type-resolver/src/PerNodeTypeResolver/VariableTypeResolver.php @@ -12,7 +12,7 @@ use PHPStan\Type\MixedType; use PHPStan\Type\Type; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -24,9 +24,9 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver @@ -38,9 +38,9 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface */ private $traitNodeScopeCollector; - public function __construct(NameResolver $nameResolver, TraitNodeScopeCollector $traitNodeScopeCollector) + public function __construct(NodeNameResolver $nodeNameResolver, TraitNodeScopeCollector $traitNodeScopeCollector) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->traitNodeScopeCollector = $traitNodeScopeCollector; } @@ -62,7 +62,7 @@ public function resolve(Node $variableNode): Type return $this->nodeTypeResolver->resolve($parentNode); } - $variableName = $this->nameResolver->getName($variableNode); + $variableName = $this->nodeNameResolver->getName($variableNode); if ($variableName === null) { return new MixedType(); } @@ -104,40 +104,44 @@ private function resolveTypesFromScope(Variable $variable, string $variableName) return $nodeScope->getVariableType($variableName); } - private function resolveNodeScope(Node $node): ?Scope + private function resolveNodeScope(Variable $variable): ?Scope { /** @var Scope|null $nodeScope */ - $nodeScope = $node->getAttribute(AttributeKey::SCOPE); + $nodeScope = $variable->getAttribute(AttributeKey::SCOPE); if ($nodeScope !== null) { return $nodeScope; } // is node in trait - $classNode = $node->getAttribute(AttributeKey::CLASS_NODE); + $classNode = $variable->getAttribute(AttributeKey::CLASS_NODE); if ($classNode instanceof Trait_) { /** @var string $traitName */ - $traitName = $node->getAttribute(AttributeKey::CLASS_NAME); - $traitNodeScope = $this->traitNodeScopeCollector->getScopeForTraitAndNode($traitName, $node); + $traitName = $variable->getAttribute(AttributeKey::CLASS_NAME); + $traitNodeScope = $this->traitNodeScopeCollector->getScopeForTraitAndNode($traitName, $variable); if ($traitNodeScope !== null) { return $traitNodeScope; } } - $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE); - if ($parentNode instanceof Node) { - $parentNodeScope = $parentNode->getAttribute(AttributeKey::SCOPE); - if ($parentNodeScope !== null) { - return $parentNodeScope; + return $this->resolveFromParentNodes($variable); + } + + private function resolveFromParentNodes(Variable $variable): ?Scope + { + $parentNodeAttributes = [AttributeKey::PARENT_NODE, AttributeKey::METHOD_NODE]; + + foreach ($parentNodeAttributes as $parentNodeAttribute) { + $parentNode = $variable->getAttribute($parentNodeAttribute); + if (! $parentNode instanceof Node) { + continue; } - } - // get nearest variable scope - $method = $node->getAttribute(AttributeKey::METHOD_NODE); - if ($method instanceof Node) { - $methodNodeScope = $method->getAttribute(AttributeKey::SCOPE); - if ($methodNodeScope !== null) { - return $methodNodeScope; + $parentNodeScope = $parentNode->getAttribute(AttributeKey::SCOPE); + if ($parentNodeScope === null) { + continue; } + + return $parentNodeScope; } return null; diff --git a/packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php b/packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php index 47b46be65397..bb7f84d4cb5c 100644 --- a/packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php +++ b/packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php @@ -14,7 +14,7 @@ use Rector\CodingStyle\Application\UseAddingCommander; use Rector\CodingStyle\Imports\ImportSkipper; use Rector\Core\Configuration\Option; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\ClassExistenceStaticHelper; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -51,9 +51,9 @@ final class DocBlockNameImporter private $useAddingCommander; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BetterStandardPrinter @@ -74,7 +74,7 @@ public function __construct( PhpDocNodeTraverser $phpDocNodeTraverser, StaticTypeMapper $staticTypeMapper, UseAddingCommander $useAddingCommander, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, BetterStandardPrinter $betterStandardPrinter, ImportSkipper $importSkipper, ParameterProvider $parameterProvider @@ -82,7 +82,7 @@ public function __construct( $this->phpDocNodeTraverser = $phpDocNodeTraverser; $this->staticTypeMapper = $staticTypeMapper; $this->useAddingCommander = $useAddingCommander; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->betterStandardPrinter = $betterStandardPrinter; $this->importSkipper = $importSkipper; $this->parameterProvider = $parameterProvider; @@ -192,7 +192,7 @@ private function isCurrentNamespaceSameShortClassAlreadyUsed( return true; } - $className = $this->nameResolver->getName($classNode); + $className = $this->nodeNameResolver->getName($classNode); if (isset($this->usedShortNameByClasses[$className][$shortenedObjectType->getShortName()])) { return $this->usedShortNameByClasses[$className][$shortenedObjectType->getShortName()]; diff --git a/packages/node-type-resolver/src/StaticTypeMapper.php b/packages/node-type-resolver/src/StaticTypeMapper.php index daf0fc2a446f..2eeb6f05fb06 100644 --- a/packages/node-type-resolver/src/StaticTypeMapper.php +++ b/packages/node-type-resolver/src/StaticTypeMapper.php @@ -10,6 +10,7 @@ use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\NullableType; +use PhpParser\Node\Stmt\Use_; use PhpParser\Node\Stmt\UseUse; use PhpParser\Node\UnionType as PhpParserUnionType; use PHPStan\Analyser\NameScope; @@ -21,7 +22,7 @@ use PHPStan\Type\Type; use Rector\Core\Exception\NotImplementedException; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\PhpDoc\PhpDocTypeMapper; use Rector\NodeTypeResolver\TypeMapper\PhpParserNodeMapper; @@ -38,9 +39,9 @@ final class StaticTypeMapper private $phpStanStaticTypeMapper; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var PhpParserNodeMapper @@ -54,12 +55,12 @@ final class StaticTypeMapper public function __construct( PHPStanStaticTypeMapper $phpStanStaticTypeMapper, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, PhpParserNodeMapper $phpParserNodeMapper, PhpDocTypeMapper $phpDocTypeMapper ) { $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->phpParserNodeMapper = $phpParserNodeMapper; $this->phpDocTypeMapper = $phpDocTypeMapper; } @@ -160,26 +161,37 @@ public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $ private function createNameScopeFromNode(Node $node): NameScope { $namespace = $node->getAttribute(AttributeKey::NAMESPACE_NAME); - $useNodes = $node->getAttribute(AttributeKey::USE_NODES); - - $uses = []; - if ($useNodes) { - foreach ($useNodes as $useNode) { - foreach ($useNode->uses as $useUse) { - /** @var UseUse $useUse */ - $aliasName = $useUse->getAlias()->name; - $useName = $this->nameResolver->getName($useUse->name); - if (! is_string($useName)) { - throw new ShouldNotHappenException(); - } - - $uses[$aliasName] = $useName; - } - } - } + /** @var Use_[] $useNodes */ + $useNodes = (array) $node->getAttribute(AttributeKey::USE_NODES); + + $uses = $this->resolveUseNamesByAlias($useNodes); $className = $node->getAttribute(AttributeKey::CLASS_NAME); return new NameScope($namespace, $uses, $className); } + + /*** + * @param Use_[] $useNodes + * @return string[] + */ + private function resolveUseNamesByAlias(array $useNodes): array + { + $useNamesByAlias = []; + + foreach ($useNodes as $useNode) { + foreach ($useNode->uses as $useUse) { + /** @var UseUse $useUse */ + $aliasName = $useUse->getAlias()->name; + $useName = $this->nodeNameResolver->getName($useUse->name); + if (! is_string($useName)) { + throw new ShouldNotHappenException(); + } + + $useNamesByAlias[$aliasName] = $useName; + } + } + + return $useNamesByAlias; + } } diff --git a/packages/node-type-resolver/src/TypeAnalyzer/ArrayTypeAnalyzer.php b/packages/node-type-resolver/src/TypeAnalyzer/ArrayTypeAnalyzer.php index ddbb740be04b..bc5b2d6f0055 100644 --- a/packages/node-type-resolver/src/TypeAnalyzer/ArrayTypeAnalyzer.php +++ b/packages/node-type-resolver/src/TypeAnalyzer/ArrayTypeAnalyzer.php @@ -20,7 +20,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeWithClassName; use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeCorrector\PregMatchTypeCorrector; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -38,9 +38,9 @@ final class ArrayTypeAnalyzer private $pregMatchTypeCorrector; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ClassManipulator @@ -50,12 +50,12 @@ final class ArrayTypeAnalyzer public function __construct( NodeTypeResolver $nodeTypeResolver, PregMatchTypeCorrector $pregMatchTypeCorrector, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ClassManipulator $classManipulator ) { $this->nodeTypeResolver = $nodeTypeResolver; $this->pregMatchTypeCorrector = $pregMatchTypeCorrector; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->classManipulator = $classManipulator; } @@ -120,7 +120,7 @@ private function isPropertyFetchWithArrayDefault(Node $node): bool return false; } - $propertyName = $this->nameResolver->getName($node->name); + $propertyName = $this->nodeNameResolver->getName($node->name); if ($propertyName === null) { return false; } diff --git a/packages/node-type-resolver/tests/NodeVisitor/FunctionMethodAndClassNodeVisitor/FunctionMethodAndClassNodeVisitorTest.php b/packages/node-type-resolver/tests/NodeVisitor/FunctionMethodAndClassNodeVisitor/FunctionMethodAndClassNodeVisitorTest.php index 145d1dde4187..903d6dfcd1e9 100644 --- a/packages/node-type-resolver/tests/NodeVisitor/FunctionMethodAndClassNodeVisitor/FunctionMethodAndClassNodeVisitorTest.php +++ b/packages/node-type-resolver/tests/NodeVisitor/FunctionMethodAndClassNodeVisitor/FunctionMethodAndClassNodeVisitorTest.php @@ -9,7 +9,7 @@ use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\NameResolver; use Rector\CodingStyle\Naming\ClassNaming; -use Rector\Core\PhpParser\Node\Resolver\NameResolver as NodeNameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\Testing\PHPUnit\AbstractNodeVisitorTestCase; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeVisitor\FunctionMethodAndClassNodeVisitor; diff --git a/packages/php-71/src/IsArrayAndDualCheckToAble.php b/packages/php-71/src/IsArrayAndDualCheckToAble.php index 33f24ece6d23..cbc76c1ab73e 100644 --- a/packages/php-71/src/IsArrayAndDualCheckToAble.php +++ b/packages/php-71/src/IsArrayAndDualCheckToAble.php @@ -11,23 +11,23 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name; use Rector\Core\PhpParser\Node\Manipulator\BinaryOpManipulator; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; final class IsArrayAndDualCheckToAble { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BinaryOpManipulator */ private $binaryOpManipulator; - public function __construct(NameResolver $nameResolver, BinaryOpManipulator $binaryOpManipulator) + public function __construct(NodeNameResolver $nodeNameResolver, BinaryOpManipulator $binaryOpManipulator) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->binaryOpManipulator = $binaryOpManipulator; } @@ -52,7 +52,7 @@ public function processBooleanOr(BooleanOr $booleanOr, string $type, string $new } /** @var FuncCall $funcCallNode */ - if ($this->nameResolver->getName($funcCallNode) !== 'is_array') { + if ($this->nodeNameResolver->getName($funcCallNode) !== 'is_array') { return null; } diff --git a/packages/php-74/src/Rector/Property/TypedPropertyRector.php b/packages/php-74/src/Rector/Property/TypedPropertyRector.php index 80425a4902fe..994a198d4b26 100644 --- a/packages/php-74/src/Rector/Property/TypedPropertyRector.php +++ b/packages/php-74/src/Rector/Property/TypedPropertyRector.php @@ -16,7 +16,7 @@ use Rector\Core\ValueObject\PhpVersionFeature; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer; -use Rector\TypeDeclaration\VendorLock\VendorLockResolver; +use Rector\VendorLocker\VendorLockResolver; /** * @source https://wiki.php.net/rfc/typed_properties_v2#proposal diff --git a/packages/php-spec-to-phpunit/src/LetManipulator.php b/packages/php-spec-to-phpunit/src/LetManipulator.php index a78a99249882..a530576b34fd 100644 --- a/packages/php-spec-to-phpunit/src/LetManipulator.php +++ b/packages/php-spec-to-phpunit/src/LetManipulator.php @@ -8,7 +8,7 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Stmt\Class_; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; final class LetManipulator { @@ -18,21 +18,21 @@ final class LetManipulator private $betterNodeFinder; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(BetterNodeFinder $betterNodeFinder, NameResolver $nameResolver) + public function __construct(BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver) { $this->betterNodeFinder = $betterNodeFinder; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function isLetNeededInClass(Class_ $class): bool { foreach ($class->getMethods() as $method) { // new test - if ($this->nameResolver->isName($method, 'test*')) { + if ($this->nodeNameResolver->isName($method, 'test*')) { continue; } @@ -43,7 +43,7 @@ function (Node $node): ?bool { return null; } - return $this->nameResolver->isName($node->name, 'beConstructedThrough'); + return $this->nodeNameResolver->isName($node->name, 'beConstructedThrough'); } ); diff --git a/packages/php-spec-to-phpunit/src/Naming/PhpSpecRenaming.php b/packages/php-spec-to-phpunit/src/Naming/PhpSpecRenaming.php index 62649c2a0427..9182b1bbd48c 100644 --- a/packages/php-spec-to-phpunit/src/Naming/PhpSpecRenaming.php +++ b/packages/php-spec-to-phpunit/src/Naming/PhpSpecRenaming.php @@ -13,7 +13,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Namespace_; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\Util\RectorStrings; use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\PackageBuilder\Strings\StringFormatConverter; @@ -26,19 +26,19 @@ final class PhpSpecRenaming private $stringFormatConverter; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(StringFormatConverter $stringFormatConverter, NameResolver $nameResolver) + public function __construct(StringFormatConverter $stringFormatConverter, NodeNameResolver $nodeNameResolver) { $this->stringFormatConverter = $stringFormatConverter; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function renameMethod(ClassMethod $classMethod): void { - $name = $this->nameResolver->getName($classMethod); + $name = $this->nodeNameResolver->getName($classMethod); if ($name === null) { return; } diff --git a/packages/php-spec-to-phpunit/src/PhpSpecMockCollector.php b/packages/php-spec-to-phpunit/src/PhpSpecMockCollector.php index c98a78408d1f..2f5590583617 100644 --- a/packages/php-spec-to-phpunit/src/PhpSpecMockCollector.php +++ b/packages/php-spec-to-phpunit/src/PhpSpecMockCollector.php @@ -10,7 +10,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -32,18 +32,18 @@ final class PhpSpecMockCollector private $propertyMocksByClass = []; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser */ private $callableNodeTraverser; - public function __construct(NameResolver $nameResolver, CallableNodeTraverser $callableNodeTraverser) + public function __construct(NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; } @@ -52,7 +52,7 @@ public function __construct(NameResolver $nameResolver, CallableNodeTraverser $c */ public function resolveClassMocksFromParam(Class_ $class): array { - $className = $this->nameResolver->getName($class); + $className = $this->nodeNameResolver->getName($class); if (isset($this->mocks[$className])) { return $this->mocks[$className]; @@ -82,7 +82,7 @@ public function resolveClassMocksFromParam(Class_ $class): array public function isVariableMockInProperty(Variable $variable): bool { - $variableName = $this->nameResolver->getName($variable); + $variableName = $this->nodeNameResolver->getName($variable); $className = $variable->getAttribute(AttributeKey::CLASS_NAME); return in_array($variableName, $this->propertyMocksByClass[$className] ?? [], true); @@ -90,7 +90,7 @@ public function isVariableMockInProperty(Variable $variable): bool public function getTypeForClassAndVariable(Class_ $node, string $variable): string { - $className = $this->nameResolver->getName($node); + $className = $this->nodeNameResolver->getName($node); if (! isset($this->mocksWithsTypes[$className][$variable])) { throw new ShouldNotHappenException(); @@ -106,7 +106,7 @@ public function addPropertyMock(string $class, string $property): void private function addMockFromParam(Param $param): void { - $variable = $this->nameResolver->getName($param->var); + $variable = $this->nodeNameResolver->getName($param->var); /** @var string $class */ $class = $param->getAttribute(AttributeKey::CLASS_NAME); diff --git a/packages/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php b/packages/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php index a42e8d2f2f4a..50c96a57520d 100644 --- a/packages/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php +++ b/packages/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php @@ -32,28 +32,13 @@ */ final class PhpSpecPromisesToPHPUnitAssertRector extends AbstractPhpSpecToPHPUnitRector { - /** - * @var string - */ - private $testedClass; - - /** - * @var bool - */ - private $isBoolAssert = false; - - /** - * @var bool - */ - private $isPrepared = false; - /** * @see https://github.com/phpspec/phpspec/blob/master/src/PhpSpec/Wrapper/Subject.php * ↓ * @see https://phpunit.readthedocs.io/en/8.0/assertions.html * @var string[][] */ - private $newMethodToOldMethods = [ + private const NEW_METHOD_TO_OLD_METHODS = [ 'assertInstanceOf' => ['shouldBeAnInstanceOf', 'shouldHaveType', 'shouldReturnAnInstanceOf'], 'assertSame' => ['shouldBe', 'shouldReturn'], 'assertNotSame' => ['shouldNotBe', 'shouldNotReturn'], @@ -90,6 +75,21 @@ final class PhpSpecPromisesToPHPUnitAssertRector extends AbstractPhpSpecToPHPUni 'assertInfinite' => ['shouldBeInfinite', 'shouldNotBeInfinite'], ]; + /** + * @var string + */ + private $testedClass; + + /** + * @var bool + */ + private $isBoolAssert = false; + + /** + * @var bool + */ + private $isPrepared = false; + /** * @var string[] */ @@ -163,22 +163,13 @@ public function refactor(Node $node): ?Node $this->processMatchersKeys($node); - foreach ($this->newMethodToOldMethods as $newMethod => $oldMethods) { + foreach (self::NEW_METHOD_TO_OLD_METHODS as $newMethod => $oldMethods) { if ($this->isNames($node->name, $oldMethods)) { return $this->createAssertMethod($newMethod, $node->var, $node->args[0]->value ?? null); } } - if (! $node->var instanceof Variable) { - return null; - } - - if (! $this->isName($node->var, 'this')) { - return null; - } - - // skip "createMock" method - if ($this->isName($node->name, 'createMock')) { + if ($this->shouldSkip($node)) { return null; } @@ -391,4 +382,18 @@ private function thisToTestedObjectPropertyFetch(Expr $expr): Expr return $this->testedObjectPropertyFetch; } + + private function shouldSkip(MethodCall $methodCall): bool + { + if (! $methodCall->var instanceof Variable) { + return true; + } + + if (! $this->isName($methodCall->var, 'this')) { + return true; + } + + // skip "createMock" method + return $this->isName($methodCall->name, 'createMock'); + } } diff --git a/packages/phpstan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php b/packages/phpstan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php index cf793aaf1975..3be84e3d17c2 100644 --- a/packages/phpstan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php +++ b/packages/phpstan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php @@ -32,6 +32,24 @@ */ final class RemoveNonExistingVarAnnotationRector extends AbstractRector { + /** + * @var class-string[] + */ + private const NODES_TO_MATCH = [ + Assign::class, + AssignRef::class, + Foreach_::class, + Static_::class, + Echo_::class, + Return_::class, + Expression::class, + Throw_::class, + If_::class, + While_::class, + Switch_::class, + Nop::class, + ]; + public function getDefinition(): RectorDefinition { return new RectorDefinition('Removes non-existing @var annotations above the code', [ @@ -101,17 +119,14 @@ public function refactor(Node $node): ?Node private function shouldSkip(Node $node): bool { - return ! $node instanceof Assign - && ! $node instanceof AssignRef - && ! $node instanceof Foreach_ - && ! $node instanceof Static_ - && ! $node instanceof Echo_ - && ! $node instanceof Return_ - && ! $node instanceof Expression - && ! $node instanceof Throw_ - && ! $node instanceof If_ - && ! $node instanceof While_ - && ! $node instanceof Switch_ - && ! $node instanceof Nop; + foreach (self::NODES_TO_MATCH as $nodeToMatch) { + if (! is_a($node, $nodeToMatch, true)) { + continue; + } + + return false; + } + + return true; } } diff --git a/packages/phpunit/src/Manipulator/OnContainerGetCallManipulator.php b/packages/phpunit/src/Manipulator/OnContainerGetCallManipulator.php index aab0ebf42c4c..2a012c3b82e3 100644 --- a/packages/phpunit/src/Manipulator/OnContainerGetCallManipulator.php +++ b/packages/phpunit/src/Manipulator/OnContainerGetCallManipulator.php @@ -11,7 +11,7 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Class_; use Rector\Core\PhpParser\Node\Commander\NodeRemovingCommander; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -21,9 +21,9 @@ final class OnContainerGetCallManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser @@ -51,14 +51,14 @@ final class OnContainerGetCallManipulator private $valueResolver; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser, ServiceNaming $serviceNaming, NodeRemovingCommander $nodeRemovingCommander, KernelTestCaseNodeAnalyzer $kernelTestCaseNodeAnalyzer, ValueResolver $valueResolver ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; $this->serviceNaming = $serviceNaming; $this->nodeRemovingCommander = $nodeRemovingCommander; @@ -81,7 +81,7 @@ public function replaceFormerVariablesWithPropertyFetch(Class_ $class, array $fo return null; } - $variableName = $this->nameResolver->getName($node); + $variableName = $this->nodeNameResolver->getName($node); if ($variableName === null) { return null; } @@ -151,7 +151,7 @@ private function processAssign( string $type, array &$formerVariablesByMethods ): void { - $variableName = $this->nameResolver->getName($assign->var); + $variableName = $this->nodeNameResolver->getName($assign->var); if ($variableName === null) { return; } diff --git a/packages/phpunit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php b/packages/phpunit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php index 12c2f0d1e3ea..f5b451b2c9c7 100644 --- a/packages/phpunit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php +++ b/packages/phpunit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php @@ -77,7 +77,9 @@ public function getDefinition(): RectorDefinition return new RectorDefinition('Move array argument from tests into data provider [configurable]', [ new ConfiguredCodeSample( <<<'PHP' -class SomeServiceTest extends \PHPUnit\Framework\TestCase +use PHPUnit\Framework\TestCase; + +class SomeServiceTest extends TestCase { public function test() { @@ -87,7 +89,9 @@ public function test() PHP , <<<'PHP' -class SomeServiceTest extends \PHPUnit\Framework\TestCase +use PHPUnit\Framework\TestCase; + +class SomeServiceTest extends TestCase { /** * @dataProvider provideData() @@ -134,12 +138,12 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $this->ensureConfigurationIsSet($this->configuration); - if (! $this->isInTestClass($node)) { return null; } + $this->ensureConfigurationIsSet($this->configuration); + $this->dataProviderClassMethodRecipes = []; $this->traverseNodesWithCallable($node->stmts, function (Node $node) { @@ -148,53 +152,7 @@ public function refactor(Node $node): ?Node } foreach ($this->configuration as $singleConfiguration) { - if (! $this->isMethodCallMatch($node, $singleConfiguration)) { - continue; - } - - if (count($node->args) !== 1) { - throw new ShouldNotHappenException(); - } - - // resolve value types - $firstArgumentValue = $node->args[0]->value; - if (! $firstArgumentValue instanceof Array_) { - // nothing we can do - return null; - } - - // rename method to new one handling non-array input - $node->name = new Identifier($singleConfiguration['new_method']); - - $dataProviderMethodName = $this->createDataProviderMethodName($node); - - $this->dataProviderClassMethodRecipes[] = new DataProviderClassMethodRecipe( - $dataProviderMethodName, - $node->args, - $this->resolveUniqueArrayStaticType($firstArgumentValue) - ); - - $node->args = []; - $paramAndArgs = $this->collectParamAndArgsFromArray( - $firstArgumentValue, - $singleConfiguration['variable_name'] - ); - foreach ($paramAndArgs as $paramAndArg) { - $node->args[] = new Arg($paramAndArg->getVariable()); - } - - /** @var ClassMethod $classMethod */ - $classMethod = $node->getAttribute(AttributeKey::METHOD_NODE); - $this->refactorTestClassMethodParams($classMethod, $paramAndArgs); - - // add data provider annotation - $dataProviderTagNode = $this->createDataProviderTagNode($dataProviderMethodName); - - /** @var PhpDocInfo $phpDocInfo */ - $phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO); - $phpDocInfo->addPhpDocTagNode($dataProviderTagNode); - - return null; + $this->refactorMethodCallWithConfiguration($node, $singleConfiguration); } return null; @@ -266,41 +224,13 @@ private function resolveUniqueArrayStaticType(Array_ $array): Type */ private function collectParamAndArgsFromArray(Array_ $array, string $variableName): array { - // multiple arguments - $i = 1; - - $paramAndArgs = []; - $isNestedArray = $this->isNestedArray($array); - - $itemsStaticType = $this->resolveItemStaticType($array, $isNestedArray); - - if (! $isNestedArray) { - foreach ($array->items as $arrayItem) { - $variable = new Variable($variableName . ($i === 1 ? '' : $i)); - - $paramAndArgs[] = new ParamAndArgValueObject($variable, $itemsStaticType); - ++$i; - - if (! $arrayItem->value instanceof Array_) { - break; - } - } - } else { - foreach ($array->items as $arrayItem) { - /** @var Array_ $nestedArray */ - $nestedArray = $arrayItem->value; - foreach ($nestedArray->items as $nestedArrayItem) { - $variable = new Variable($variableName . ($i === 1 ? '' : $i)); - - $itemsStaticType = $this->getStaticType($nestedArrayItem->value); - $paramAndArgs[] = new ParamAndArgValueObject($variable, $itemsStaticType); - ++$i; - } - } + if ($isNestedArray) { + return $this->collectParamAndArgsFromNestedArray($array, $variableName); } - return $paramAndArgs; + $itemsStaticType = $this->resolveItemStaticType($array, $isNestedArray); + return $this->collectParamAndArgsFromNonNestedArray($array, $variableName, $itemsStaticType); } /** @@ -422,4 +352,103 @@ private function createParamTagNode(string $name, TypeNode $typeNode): Attribute { return new AttributeAwareParamTagValueNode($typeNode, false, '$' . $name, '', false); } + + private function refactorMethodCallWithConfiguration(MethodCall $methodCall, array $singleConfiguration): void + { + if (! $this->isMethodCallMatch($methodCall, $singleConfiguration)) { + return; + } + + if (count($methodCall->args) !== 1) { + throw new ShouldNotHappenException(); + } + + // resolve value types + $firstArgumentValue = $methodCall->args[0]->value; + if (! $firstArgumentValue instanceof Array_) { + // nothing we can do + return; + } + + // rename method to new one handling non-array input + $methodCall->name = new Identifier($singleConfiguration['new_method']); + + $dataProviderMethodName = $this->createDataProviderMethodName($methodCall); + + $this->dataProviderClassMethodRecipes[] = new DataProviderClassMethodRecipe( + $dataProviderMethodName, + $methodCall->args, + $this->resolveUniqueArrayStaticType($firstArgumentValue) + ); + + $methodCall->args = []; + + $paramAndArgs = $this->collectParamAndArgsFromArray( + $firstArgumentValue, + $singleConfiguration['variable_name'] + ); + + foreach ($paramAndArgs as $paramAndArg) { + $methodCall->args[] = new Arg($paramAndArg->getVariable()); + } + + /** @var ClassMethod $classMethod */ + $classMethod = $methodCall->getAttribute(AttributeKey::METHOD_NODE); + + $this->refactorTestClassMethodParams($classMethod, $paramAndArgs); + + // add data provider annotation + $dataProviderTagNode = $this->createDataProviderTagNode($dataProviderMethodName); + + /** @var PhpDocInfo $phpDocInfo */ + $phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO); + $phpDocInfo->addPhpDocTagNode($dataProviderTagNode); + } + + /** + * @return ParamAndArgValueObject[] + */ + private function collectParamAndArgsFromNonNestedArray( + Array_ $array, + string $variableName, + Type $itemsStaticType + ): array { + $i = 1; + $paramAndArgs = []; + + foreach ($array->items as $arrayItem) { + $variable = new Variable($variableName . ($i === 1 ? '' : $i)); + + $paramAndArgs[] = new ParamAndArgValueObject($variable, $itemsStaticType); + ++$i; + + if (! $arrayItem->value instanceof Array_) { + break; + } + } + + return $paramAndArgs; + } + + /** + * @return ParamAndArgValueObject[] + */ + private function collectParamAndArgsFromNestedArray(Array_ $array, string $variableName): array + { + $paramAndArgs = []; + $i = 1; + + foreach ($array->items as $arrayItem) { + /** @var Array_ $nestedArray */ + $nestedArray = $arrayItem->value; + foreach ($nestedArray->items as $nestedArrayItem) { + $variable = new Variable($variableName . ($i === 1 ? '' : $i)); + + $itemsStaticType = $this->getStaticType($nestedArrayItem->value); + $paramAndArgs[] = new ParamAndArgValueObject($variable, $itemsStaticType); + ++$i; + } + } + return $paramAndArgs; + } } diff --git a/packages/polyfill/src/ConditionResolver.php b/packages/polyfill/src/ConditionResolver.php index 6688036df654..6c17fd47e299 100644 --- a/packages/polyfill/src/ConditionResolver.php +++ b/packages/polyfill/src/ConditionResolver.php @@ -12,7 +12,7 @@ use PhpParser\Node\Expr\BinaryOp\NotIdentical; use PhpParser\Node\Expr\FuncCall; use Rector\Core\Php\PhpVersionProvider; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\Polyfill\Contract\ConditionInterface; use Rector\Polyfill\ValueObject\BinaryToVersionCompareCondition; @@ -21,9 +21,9 @@ final class ConditionResolver { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ValueResolver @@ -36,11 +36,11 @@ final class ConditionResolver private $phpVersionProvider; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ValueResolver $valueResolver, PhpVersionProvider $phpVersionProvider ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->valueResolver = $valueResolver; $this->phpVersionProvider = $phpVersionProvider; } @@ -87,7 +87,7 @@ private function isVersionCompareFuncCall(Node $node): bool return false; } - return $this->nameResolver->isName($node, 'version_compare'); + return $this->nodeNameResolver->isName($node, 'version_compare'); } private function resolveVersionCompareConditionForFuncCall(FuncCall $funcCall) diff --git a/packages/removing-static/src/Printer/FactoryClassPrinter.php b/packages/removing-static/src/Printer/FactoryClassPrinter.php index e915c2524553..fccdbb7fd77b 100644 --- a/packages/removing-static/src/Printer/FactoryClassPrinter.php +++ b/packages/removing-static/src/Printer/FactoryClassPrinter.php @@ -9,7 +9,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Namespace_; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\Node\AttributeKey; use Symfony\Component\Filesystem\Filesystem; @@ -18,9 +18,9 @@ final class FactoryClassPrinter { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BetterStandardPrinter @@ -33,11 +33,11 @@ final class FactoryClassPrinter private $filesystem; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, BetterStandardPrinter $betterStandardPrinter, Filesystem $filesystem ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->betterStandardPrinter = $betterStandardPrinter; $this->filesystem = $filesystem; } @@ -69,7 +69,7 @@ private function createFactoryClassFilePath(Class_ $oldClass): string } $directoryPath = Strings::before($classFileInfo->getRealPath(), DIRECTORY_SEPARATOR, -1); - $resolvedOldClass = $this->nameResolver->getName($oldClass); + $resolvedOldClass = $this->nodeNameResolver->getName($oldClass); if ($resolvedOldClass === null) { throw new ShouldNotHappenException(); } diff --git a/packages/removing-static/src/UniqueObjectFactoryFactory.php b/packages/removing-static/src/UniqueObjectFactoryFactory.php index f568ce514f33..f8c5ca6216b7 100644 --- a/packages/removing-static/src/UniqueObjectFactoryFactory.php +++ b/packages/removing-static/src/UniqueObjectFactoryFactory.php @@ -22,16 +22,16 @@ use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\Naming\PropertyNaming; use Rector\Core\PhpParser\Node\NodeFactory; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\StaticTypeMapper; final class UniqueObjectFactoryFactory { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BuilderFactory @@ -54,13 +54,13 @@ final class UniqueObjectFactoryFactory private $nodeFactory; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, BuilderFactory $builderFactory, PropertyNaming $propertyNaming, StaticTypeMapper $staticTypeMapper, NodeFactory $nodeFactory ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->builderFactory = $builderFactory; $this->propertyNaming = $propertyNaming; $this->staticTypeMapper = $staticTypeMapper; @@ -69,7 +69,7 @@ public function __construct( public function createFactoryClass(Class_ $class, ObjectType $objectType): Class_ { - $className = $this->nameResolver->getName($class); + $className = $this->nodeNameResolver->getName($class); if ($className === null) { throw new ShouldNotHappenException(); } @@ -163,7 +163,7 @@ private function createCreateMethod(Class_ $class, string $className, array $pro } foreach ($properties as $property) { - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); if (! is_string($propertyName)) { throw new ShouldNotHappenException(); } diff --git a/packages/sensio/src/Helper/TemplateGuesser.php b/packages/sensio/src/Helper/TemplateGuesser.php index e0b9d46c72ab..e10b81815037 100644 --- a/packages/sensio/src/Helper/TemplateGuesser.php +++ b/packages/sensio/src/Helper/TemplateGuesser.php @@ -7,7 +7,7 @@ use Nette\Utils\Strings; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; /** @@ -17,13 +17,13 @@ final class TemplateGuesser { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NameResolver $nameResolver) + public function __construct(NodeNameResolver $nodeNameResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function resolveFromClassMethodNode(ClassMethod $classMethod, int $version = 5): string @@ -38,7 +38,7 @@ public function resolveFromClassMethodNode(ClassMethod $classMethod, int $versio throw new ShouldNotHappenException(); } - $method = $this->nameResolver->getName($classMethod); + $method = $this->nodeNameResolver->getName($classMethod); if ($method === null) { throw new ShouldNotHappenException(); } diff --git a/packages/solid/src/Analyzer/ClassConstantFetchAnalyzer.php b/packages/solid/src/Analyzer/ClassConstantFetchAnalyzer.php index 0cd2676b942a..393f54946f61 100644 --- a/packages/solid/src/Analyzer/ClassConstantFetchAnalyzer.php +++ b/packages/solid/src/Analyzer/ClassConstantFetchAnalyzer.php @@ -9,7 +9,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeUtils; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\Testing\PHPUnit\PHPUnitEnvironment; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -22,9 +22,9 @@ final class ClassConstantFetchAnalyzer private $classConstantFetchByClassAndName = []; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver @@ -38,11 +38,11 @@ final class ClassConstantFetchAnalyzer public function __construct( NodeTypeResolver $nodeTypeResolver, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ParsedNodeCollector $parsedNodeCollector ) { $this->nodeTypeResolver = $nodeTypeResolver; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parsedNodeCollector = $parsedNodeCollector; } @@ -66,7 +66,7 @@ public function provideClassConstantFetchByClassAndName(): array private function addClassConstantFetch(ClassConstFetch $classConstFetch): void { - $constantName = $this->nameResolver->getName($classConstFetch->name); + $constantName = $this->nodeNameResolver->getName($classConstFetch->name); if ($constantName === 'class' || $constantName === null) { // this is not a manual constant @@ -105,7 +105,7 @@ private function matchClassTypeThatContainsConstant(Type $type, string $constant } foreach ($classOrInterface->getConstants() as $classConstant) { - if ($this->nameResolver->isName($classConstant, $constant)) { + if ($this->nodeNameResolver->isName($classConstant, $constant)) { return $className; } } diff --git a/packages/symfony-phpunit/src/Node/KernelTestCaseNodeAnalyzer.php b/packages/symfony-phpunit/src/Node/KernelTestCaseNodeAnalyzer.php index d4867cc6e453..a75a23dea2b6 100644 --- a/packages/symfony-phpunit/src/Node/KernelTestCaseNodeAnalyzer.php +++ b/packages/symfony-phpunit/src/Node/KernelTestCaseNodeAnalyzer.php @@ -6,7 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -14,18 +14,18 @@ final class KernelTestCaseNodeAnalyzer { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver */ private $nodeTypeResolver; - public function __construct(NameResolver $nameResolver, NodeTypeResolver $nodeTypeResolver) + public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; } @@ -54,7 +54,7 @@ private function isSelfContainerGetMethodCall(Node $node): bool return false; } - if (! $this->nameResolver->isName($node->name, 'get')) { + if (! $this->nodeNameResolver->isName($node->name, 'get')) { return false; } diff --git a/packages/symfony/src/Rector/Class_/MakeCommandLazyRector.php b/packages/symfony/src/Rector/Class_/MakeCommandLazyRector.php index 03e886ee893c..f5d1fdd86990 100644 --- a/packages/symfony/src/Rector/Class_/MakeCommandLazyRector.php +++ b/packages/symfony/src/Rector/Class_/MakeCommandLazyRector.php @@ -19,6 +19,7 @@ /** * @see https://symfony.com/doc/current/console/commands_as_services.html * @sponsor Thanks https://www.musement.com/ for sponsoring this rule; initiated by https://github.com/stloyd + * * @see \Rector\Symfony\Tests\Rector\Class_\MakeCommandLazyRector\MakeCommandLazyRectorTest */ final class MakeCommandLazyRector extends AbstractRector @@ -88,40 +89,10 @@ public function refactor(Node $node): ?Node private function resolveCommandNameAndRemove(Class_ $class): ?Node { - $commandName = null; - - $this->traverseNodesWithCallable((array) $class->stmts, function (Node $node) use (&$commandName) { - if ($node instanceof MethodCall) { - if (! $this->isObjectType($node->var, Command::class)) { - return null; - } - - if (! $this->isName($node->name, 'setName')) { - return null; - } - - $commandName = $node->args[0]->value; - $commandNameStaticType = $this->getStaticType($commandName); - if (! $commandNameStaticType instanceof StringType) { - return null; - } - - $this->removeNode($node); - } - - if ($node instanceof StaticCall) { - if (! $this->isObjectType($node->class, Command::class)) { - return null; - } - - $commandName = $this->matchCommandNameNodeInConstruct($node); - if ($commandName === null) { - return null; - } - - array_shift($node->args); - } - }); + $commandName = $this->resolveCommandNameFromConstructor($class); + if ($commandName === null) { + $commandName = $this->resolveCommandNameFromSetName($class); + } $this->removeConstructorIfHasOnlySetNameMethodCall($class); @@ -181,4 +152,55 @@ private function removeConstructorIfHasOnlySetNameMethodCall(Class_ $class): voi $this->removeNode($constructClassMethod); } + + private function resolveCommandNameFromConstructor(Class_ $class): ?Node + { + $commandName = null; + + $this->traverseNodesWithCallable((array) $class->stmts, function (Node $node) use (&$commandName) { + if (! $node instanceof StaticCall) { + return null; + } + if (! $this->isObjectType($node->class, Command::class)) { + return null; + } + + $commandName = $this->matchCommandNameNodeInConstruct($node); + if ($commandName === null) { + return null; + } + + array_shift($node->args); + }); + + return $commandName; + } + + private function resolveCommandNameFromSetName(Class_ $class): ?Node + { + $commandName = null; + + $this->traverseNodesWithCallable((array) $class->stmts, function (Node $node) use (&$commandName) { + if (! $node instanceof MethodCall) { + return null; + } + if (! $this->isObjectType($node->var, Command::class)) { + return null; + } + + if (! $this->isName($node->name, 'setName')) { + return null; + } + + $commandName = $node->args[0]->value; + $commandNameStaticType = $this->getStaticType($commandName); + if (! $commandNameStaticType instanceof StringType) { + return null; + } + + $this->removeNode($node); + }); + + return $commandName; + } } diff --git a/packages/type-declaration/src/PhpDocParser/ParamPhpDocNodeFactory.php b/packages/type-declaration/src/PhpDocParser/ParamPhpDocNodeFactory.php index 7f7536416b16..a2bbb90d5dde 100644 --- a/packages/type-declaration/src/PhpDocParser/ParamPhpDocNodeFactory.php +++ b/packages/type-declaration/src/PhpDocParser/ParamPhpDocNodeFactory.php @@ -7,24 +7,24 @@ use PhpParser\Node\Param; use PHPStan\Type\Type; use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareParamTagValueNode; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\StaticTypeMapper; final class ParamPhpDocNodeFactory { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var StaticTypeMapper */ private $staticTypeMapper; - public function __construct(NameResolver $nameResolver, StaticTypeMapper $staticTypeMapper) + public function __construct(NodeNameResolver $nodeNameResolver, StaticTypeMapper $staticTypeMapper) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->staticTypeMapper = $staticTypeMapper; } @@ -35,7 +35,7 @@ public function create(Type $type, Param $param): AttributeAwareParamTagValueNod return new AttributeAwareParamTagValueNode( $typeNode, $param->variadic, - '$' . $this->nameResolver->getName($param), + '$' . $this->nodeNameResolver->getName($param), '', $param->byRef ); diff --git a/packages/type-declaration/src/PhpParserTypeAnalyzer.php b/packages/type-declaration/src/PhpParserTypeAnalyzer.php index 4ec6e74c187c..cf51aff43f2a 100644 --- a/packages/type-declaration/src/PhpParserTypeAnalyzer.php +++ b/packages/type-declaration/src/PhpParserTypeAnalyzer.php @@ -34,32 +34,42 @@ public function isSubtypeOf(Node $possibleSubtype, Node $possibleParentType): bo } // unwrap nullable types - if ($possibleParentType instanceof NullableType) { - $possibleParentType = $possibleParentType->type; - } - - if ($possibleSubtype instanceof NullableType) { - $possibleSubtype = $possibleSubtype->type; - } + $possibleParentType = $this->unwrapNullableAndToString($possibleParentType); + $possibleSubtype = $this->unwrapNullableAndToString($possibleSubtype); - $possibleSubtype = $possibleSubtype->toString(); - $possibleParentType = $possibleParentType->toString(); if (is_a($possibleSubtype, $possibleParentType, true)) { return true; } - if (in_array($possibleSubtype, ['array', 'Traversable'], true) && $possibleParentType === 'iterable') { + if ($this->isTraversableOrIterableSubtype($possibleSubtype, $possibleParentType)) { return true; } - if (in_array($possibleSubtype, ['array', 'ArrayIterator'], true) && $possibleParentType === 'countable') { + if ($possibleParentType === $possibleSubtype) { return true; } - if ($possibleParentType === $possibleSubtype) { + return ctype_upper($possibleSubtype[0]) && $possibleParentType === 'object'; + } + + /** + * @param Name|NullableType|Identifier $node + */ + private function unwrapNullableAndToString(Node $node): string + { + if (! $node instanceof NullableType) { + return $node->toString(); + } + + return $node->type->toString(); + } + + private function isTraversableOrIterableSubtype(string $possibleSubtype, string $possibleParentType): bool + { + if (in_array($possibleSubtype, ['array', 'Traversable'], true) && $possibleParentType === 'iterable') { return true; } - return ctype_upper($possibleSubtype[0]) && $possibleParentType === 'object'; + return in_array($possibleSubtype, ['array', 'ArrayIterator'], true) && $possibleParentType === 'countable'; } } diff --git a/packages/type-declaration/src/Rector/FunctionLike/AbstractTypeDeclarationRector.php b/packages/type-declaration/src/Rector/FunctionLike/AbstractTypeDeclarationRector.php index ccf07d3aaeaf..aa80000a3500 100644 --- a/packages/type-declaration/src/Rector/FunctionLike/AbstractTypeDeclarationRector.php +++ b/packages/type-declaration/src/Rector/FunctionLike/AbstractTypeDeclarationRector.php @@ -20,7 +20,7 @@ use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator; use Rector\PHPStan\Type\SelfObjectType; use Rector\TypeDeclaration\PhpParserTypeAnalyzer; -use Rector\TypeDeclaration\VendorLock\VendorLockResolver; +use Rector\VendorLocker\VendorLockResolver; /** * @see https://wiki.php.net/rfc/scalar_type_hints_v5 diff --git a/packages/type-declaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php b/packages/type-declaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php index 2edc08a6daf1..4380490147b1 100644 --- a/packages/type-declaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php +++ b/packages/type-declaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php @@ -143,7 +143,7 @@ public function refactor(Node $node): ?Node } $position = (int) $position; - if ($node instanceof ClassMethod && $this->vendorLockResolver->isParameterChangeVendorLockedIn( + if ($node instanceof ClassMethod && $this->vendorLockResolver->isParamChangeVendorLockedIn( $node, $position )) { diff --git a/packages/type-declaration/src/TypeInferer/AbstractTypeInferer.php b/packages/type-declaration/src/TypeInferer/AbstractTypeInferer.php index 8edca81f5061..caeeb853e65c 100644 --- a/packages/type-declaration/src/TypeInferer/AbstractTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/AbstractTypeInferer.php @@ -4,7 +4,7 @@ namespace Rector\TypeDeclaration\TypeInferer; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory; @@ -18,9 +18,9 @@ abstract class AbstractTypeInferer protected $callableNodeTraverser; /** - * @var NameResolver + * @var NodeNameResolver */ - protected $nameResolver; + protected $nodeNameResolver; /** * @var NodeTypeResolver @@ -42,13 +42,13 @@ abstract class AbstractTypeInferer */ public function autowireAbstractTypeInferer( CallableNodeTraverser $callableNodeTraverser, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, StaticTypeMapper $staticTypeMapper, TypeFactory $typeFactory ): void { $this->callableNodeTraverser = $callableNodeTraverser; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; $this->staticTypeMapper = $staticTypeMapper; $this->typeFactory = $typeFactory; diff --git a/packages/type-declaration/src/TypeInferer/AssignToPropertyTypeInferer.php b/packages/type-declaration/src/TypeInferer/AssignToPropertyTypeInferer.php index 1293a951cd5e..c723bc32a3e2 100644 --- a/packages/type-declaration/src/TypeInferer/AssignToPropertyTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/AssignToPropertyTypeInferer.php @@ -59,7 +59,7 @@ public function inferPropertyInClassLike(string $propertyName, ClassLike $classL private function matchPropertyAssignExpr(Assign $assign, string $propertyName): ?Expr { if ($this->isPropertyFetch($assign->var)) { - if (! $this->nameResolver->isName($assign->var, $propertyName)) { + if (! $this->nodeNameResolver->isName($assign->var, $propertyName)) { return null; } @@ -67,7 +67,7 @@ private function matchPropertyAssignExpr(Assign $assign, string $propertyName): } if ($assign->var instanceof ArrayDimFetch && $this->isPropertyFetch($assign->var->var)) { - if (! $this->nameResolver->isName($assign->var->var, $propertyName)) { + if (! $this->nodeNameResolver->isName($assign->var->var, $propertyName)) { return null; } diff --git a/packages/type-declaration/src/TypeInferer/ParamTypeInferer/GetterNodeParamTypeInferer.php b/packages/type-declaration/src/TypeInferer/ParamTypeInferer/GetterNodeParamTypeInferer.php index 7da7894d537a..6b168f2178af 100644 --- a/packages/type-declaration/src/TypeInferer/ParamTypeInferer/GetterNodeParamTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/ParamTypeInferer/GetterNodeParamTypeInferer.php @@ -42,7 +42,7 @@ public function inferParam(Param $param): Type $classMethod = $param->getAttribute(AttributeKey::PARENT_NODE); /** @var string $paramName */ - $paramName = $this->nameResolver->getName($param); + $paramName = $this->nodeNameResolver->getName($param); $propertyNames = $this->propertyFetchManipulator->getPropertyNamesOfAssignOfVariable($classMethod, $paramName); if ($propertyNames === []) { diff --git a/packages/type-declaration/src/TypeInferer/ParamTypeInferer/PropertyNodeParamTypeInferer.php b/packages/type-declaration/src/TypeInferer/ParamTypeInferer/PropertyNodeParamTypeInferer.php index 3535290f5eba..f4c4d9aa9db9 100644 --- a/packages/type-declaration/src/TypeInferer/ParamTypeInferer/PropertyNodeParamTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/ParamTypeInferer/PropertyNodeParamTypeInferer.php @@ -37,7 +37,7 @@ public function inferParam(Param $param): Type return new MixedType(); } - $paramName = $this->nameResolver->getName($param); + $paramName = $this->nodeNameResolver->getName($param); if (! is_string($paramName)) { throw new ShouldNotHappenException(); } diff --git a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php index 1159348dbf31..daddaf41af88 100644 --- a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php @@ -35,7 +35,7 @@ public function inferProperty(Property $property): Type return new MixedType(); } - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); if (! is_string($propertyName)) { throw new ShouldNotHappenException(); } diff --git a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php index c20c1732ca39..f8b21b839e29 100644 --- a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php @@ -53,7 +53,7 @@ public function inferProperty(Property $property): Type return new MixedType(); } - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); if (! is_string($propertyName)) { throw new ShouldNotHappenException(); } @@ -65,25 +65,7 @@ public function inferProperty(Property $property): Type // A. infer from type declaration of parameter if ($param->type !== null) { - $type = $this->resolveParamTypeToPHPStanType($param); - if ($type instanceof MixedType) { - return new MixedType(); - } - - $types = []; - - // it's an array - annotation → make type more precise, if possible - if ($type instanceof ArrayType) { - $types[] = $this->getResolveParamStaticTypeAsPHPStanType($classMethod, $propertyName); - } else { - $types[] = $type; - } - - if ($this->isParamNullable($param)) { - $types[] = new NullType(); - } - - return $this->typeFactory->createMixedPassedOrUnionType($types); + return $this->resolveFromParamType($param, $classMethod, $propertyName); } return new MixedType(); @@ -131,7 +113,7 @@ private function getResolveParamStaticTypeAsPHPStanType(ClassMethod $classMethod return null; } - if (! $this->nameResolver->isName($node, $propertyName)) { + if (! $this->nodeNameResolver->isName($node, $propertyName)) { return null; } @@ -165,7 +147,7 @@ private function resolveFullyQualifiedOrAliasedObjectType(Param $param): ?Type return null; } - $fullyQualifiedName = $this->nameResolver->getName($param->type); + $fullyQualifiedName = $this->nodeNameResolver->getName($param->type); if (! $fullyQualifiedName) { return null; } @@ -189,4 +171,27 @@ private function resolveFullyQualifiedOrAliasedObjectType(Param $param): ?Type return null; } + + private function resolveFromParamType(Param $param, ClassMethod $classMethod, string $propertyName): Type + { + $type = $this->resolveParamTypeToPHPStanType($param); + if ($type instanceof MixedType) { + return new MixedType(); + } + + $types = []; + + // it's an array - annotation → make type more precise, if possible + if ($type instanceof ArrayType) { + $types[] = $this->getResolveParamStaticTypeAsPHPStanType($classMethod, $propertyName); + } else { + $types[] = $type; + } + + if ($this->isParamNullable($param)) { + $types[] = new NullType(); + } + + return $this->typeFactory->createMixedPassedOrUnionType($types); + } } diff --git a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php index c8460fa4da9b..b734916c3f51 100644 --- a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php @@ -55,7 +55,7 @@ public function inferProperty(Property $property): Type } /** @var string $propertyName */ - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); foreach ($class->getMethods() as $classMethod) { if (! $this->hasClassMethodOnlyStatementReturnOfPropertyFetch($classMethod, $propertyName)) { @@ -97,7 +97,7 @@ private function hasClassMethodOnlyStatementReturnOfPropertyFetch( return false; } - return $this->nameResolver->isName($return->expr, $propertyName); + return $this->nodeNameResolver->isName($return->expr, $propertyName); } private function inferClassMethodReturnType(ClassMethod $classMethod): Type diff --git a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php index 9ab6484d5968..98b126429b52 100644 --- a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php @@ -39,7 +39,7 @@ public function inferProperty(Property $property): Type } /** @var string $propertyName */ - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); foreach ($class->getMethods() as $classMethod) { if (! $this->hasClassMethodOnlyStatementReturnOfPropertyFetch($classMethod, $propertyName)) { @@ -87,6 +87,6 @@ private function hasClassMethodOnlyStatementReturnOfPropertyFetch( return false; } - return $this->nameResolver->isName($return->expr, $propertyName); + return $this->nodeNameResolver->isName($return->expr, $propertyName); } } diff --git a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/SingleMethodAssignedNodePropertyTypeInferer.php b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/SingleMethodAssignedNodePropertyTypeInferer.php index 4c3644e3d578..43841375a1d9 100644 --- a/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/SingleMethodAssignedNodePropertyTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/PropertyTypeInferer/SingleMethodAssignedNodePropertyTypeInferer.php @@ -33,7 +33,7 @@ public function inferProperty(Property $property): Type return new MixedType(); } - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); $assignedNode = $this->resolveAssignedNodeToProperty($classMethod, $propertyName); if ($assignedNode === null) { @@ -59,7 +59,7 @@ private function resolveAssignedNodeToProperty(ClassMethod $classMethod, string return null; } - if (! $this->nameResolver->isName($node->var, $propertyName)) { + if (! $this->nodeNameResolver->isName($node->var, $propertyName)) { return null; } diff --git a/packages/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php b/packages/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php index 7449fc9dfeda..12e024438f44 100644 --- a/packages/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php +++ b/packages/type-declaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php @@ -30,7 +30,7 @@ public function inferFunctionLike(FunctionLike $functionLike): Type } // resolve later with more precise type, e.g. Type[] - if ($this->nameResolver->isNames($functionLike->getReturnType(), ['array', 'iterable'])) { + if ($this->nodeNameResolver->isNames($functionLike->getReturnType(), ['array', 'iterable'])) { return new MixedType(); } diff --git a/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc b/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc index 57e8b8c6b66f..7687984b57b3 100644 --- a/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc +++ b/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc @@ -595,7 +595,7 @@ class Command */ private $processTitle; /** - * @var \Symfony\Component\Console\Input\InputDefinition + * @var InputDefinition */ private $definition; /** diff --git a/packages/vendor-locker/config/config.yaml b/packages/vendor-locker/config/config.yaml new file mode 100644 index 000000000000..f4b3af24beb3 --- /dev/null +++ b/packages/vendor-locker/config/config.yaml @@ -0,0 +1,7 @@ +services: + _defaults: + public: true + autowire: true + + Rector\VendorLocker\: + resource: '../src' diff --git a/packages/vendor-locker/src/Contract/NodeVendorLockerInterface.php b/packages/vendor-locker/src/Contract/NodeVendorLockerInterface.php new file mode 100644 index 000000000000..8d48221b4268 --- /dev/null +++ b/packages/vendor-locker/src/Contract/NodeVendorLockerInterface.php @@ -0,0 +1,12 @@ +nodeNameResolver = $nodeNameResolver; + $this->parsedNodeCollector = $parsedNodeCollector; + $this->classManipulator = $classManipulator; + } + + public function isVendorLocked(ClassMethod $classMethod): bool + { + $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); + if ($classNode === null) { + return false; + } + + if (! $this->hasParentClassOrImplementsInterface($classNode)) { + return false; + } + + /** @var string $methodName */ + $methodName = $this->nodeNameResolver->getName($classMethod); + + // @todo extract to some "inherited parent method" service + /** @var string|null $parentClassName */ + $parentClassName = $classMethod->getAttribute(AttributeKey::PARENT_CLASS_NAME); + + if ($parentClassName !== null) { + return $this->isVendorLockedByParentClass($parentClassName, $methodName); + } + + $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); + if (! $classNode instanceof Class_ && ! $classNode instanceof Interface_) { + return false; + } + + $interfaceNames = $this->classManipulator->getClassLikeNodeParentInterfaceNames($classNode); + + return $this->isVendorLockedByInterface($interfaceNames, $methodName); + } + + private function hasParentClassOrImplementsInterface(ClassLike $classLike): bool + { + if (($classLike instanceof Class_ || $classLike instanceof Interface_) && $classLike->extends) { + return true; + } + + if ($classLike instanceof Class_) { + return (bool) $classLike->implements; + } + + return false; + } + + private function isVendorLockedByParentClass(string $parentClassName, string $methodName): bool + { + $parentClassNode = $this->parsedNodeCollector->findClass($parentClassName); + if ($parentClassNode !== null) { + $parentMethodNode = $parentClassNode->getMethod($methodName); + // @todo validate type is conflicting + // parent class method in local scope → it's ok + if ($parentMethodNode !== null) { + return $parentMethodNode->returnType !== null; + } + + // if not, look for it's parent parent - @todo recursion + } + + if (method_exists($parentClassName, $methodName)) { + // @todo validate type is conflicting + // parent class method in external scope → it's not ok + return true; + + // if not, look for it's parent parent - @todo recursion + } + + return false; + } + + /** + * @param string[] $interfaceNames + */ + private function isVendorLockedByInterface(array $interfaceNames, string $methodName): bool + { + foreach ($interfaceNames as $interfaceName) { + $interface = $this->parsedNodeCollector->findInterface($interfaceName); + // parent class method in local scope → it's ok + // @todo validate type is conflicting + if ($interface !== null && $interface->getMethod($methodName) !== null) { + return false; + } + + if (method_exists($interfaceName, $methodName)) { + // parent class method in external scope → it's not ok + // @todo validate type is conflicting + return true; + } + } + + return false; + } +} diff --git a/packages/type-declaration/src/VendorLock/VendorLockResolver.php b/packages/vendor-locker/src/VendorLockResolver.php similarity index 56% rename from packages/type-declaration/src/VendorLock/VendorLockResolver.php rename to packages/vendor-locker/src/VendorLockResolver.php index 2c8d23a9c9d9..336215192f24 100644 --- a/packages/type-declaration/src/VendorLock/VendorLockResolver.php +++ b/packages/vendor-locker/src/VendorLockResolver.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\TypeDeclaration\VendorLock; +namespace Rector\VendorLocker; use PhpParser\Node; use PhpParser\Node\Stmt\Class_; @@ -10,20 +10,22 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Property; -use PhpParser\Node\Stmt\PropertyProperty; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use ReflectionClass; +/** + * @todo decouple to standalone package "packages/vendor-locker" + */ final class VendorLockResolver { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ClassManipulator @@ -35,18 +37,26 @@ final class VendorLockResolver */ private $parsedNodeCollector; + /** + * @var ReturnNodeVendorLockResolver + */ + private $returnNodeVendorLockResolver; + public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ParsedNodeCollector $parsedNodeCollector, - ClassManipulator $classManipulator + ClassManipulator $classManipulator, + ReturnNodeVendorLockResolver $returnNodeVendorLockResolver ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parsedNodeCollector = $parsedNodeCollector; $this->classManipulator = $classManipulator; + $this->returnNodeVendorLockResolver = $returnNodeVendorLockResolver; } - public function isParameterChangeVendorLockedIn(ClassMethod $classMethod, int $paramPosition): bool + public function isParamChangeVendorLockedIn(ClassMethod $classMethod, int $paramPosition): bool { + /** @var Class_|null $classNode */ $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); if ($classNode === null) { return false; @@ -56,7 +66,7 @@ public function isParameterChangeVendorLockedIn(ClassMethod $classMethod, int $p return false; } - $methodName = $this->nameResolver->getName($classMethod); + $methodName = $this->nodeNameResolver->getName($classMethod); if (! is_string($methodName)) { throw new ShouldNotHappenException(); } @@ -66,25 +76,9 @@ public function isParameterChangeVendorLockedIn(ClassMethod $classMethod, int $p $parentClassName = $classMethod->getAttribute(AttributeKey::PARENT_CLASS_NAME); if ($parentClassName !== null) { - $parentClassNode = $this->parsedNodeCollector->findClass($parentClassName); - if ($parentClassNode !== null) { - $parentMethodNode = $parentClassNode->getMethod($methodName); - // @todo validate type is conflicting - // parent class method in local scope → it's ok - if ($parentMethodNode !== null) { - // parent method has no type → we cannot change it here - return isset($parentMethodNode->params[$paramPosition]) && $parentMethodNode->params[$paramPosition]->type === null; - } - - // if not, look for it's parent parent - @todo recursion - } - - if (method_exists($parentClassName, $methodName)) { - // @todo validate type is conflicting - // parent class method in external scope → it's not ok - return true; - - // if not, look for it's parent parent - @todo recursion + $vendorLock = $this->isParentClassVendorLocking($paramPosition, $parentClassName, $methodName); + if ($vendorLock !== null) { + return $vendorLock; } } @@ -94,92 +88,17 @@ public function isParameterChangeVendorLockedIn(ClassMethod $classMethod, int $p } $interfaceNames = $this->classManipulator->getClassLikeNodeParentInterfaceNames($classNode); - foreach ($interfaceNames as $interfaceName) { - $interface = $this->parsedNodeCollector->findInterface($interfaceName); - // parent class method in local scope → it's ok - // @todo validate type is conflicting - if ($interface !== null && $interface->getMethod($methodName) !== null) { - return false; - } - - if (method_exists($interfaceName, $methodName)) { - // parent class method in external scope → it's not ok - // @todo validate type is conflicting - return true; - } - } - - return false; + return $this->isInterfaceParamVendorLockin($interfaceNames, $methodName); } public function isReturnChangeVendorLockedIn(ClassMethod $classMethod): bool { - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if ($classNode === null) { - return false; - } - - if (! $this->hasParentClassOrImplementsInterface($classNode)) { - return false; - } - - $methodName = $this->nameResolver->getName($classMethod); - if (! is_string($methodName)) { - throw new ShouldNotHappenException(); - } - - // @todo extract to some "inherited parent method" service - /** @var string|null $parentClassName */ - $parentClassName = $classMethod->getAttribute(AttributeKey::PARENT_CLASS_NAME); - - if ($parentClassName !== null) { - $parentClassNode = $this->parsedNodeCollector->findClass($parentClassName); - if ($parentClassNode !== null) { - $parentMethodNode = $parentClassNode->getMethod($methodName); - // @todo validate type is conflicting - // parent class method in local scope → it's ok - if ($parentMethodNode !== null) { - return $parentMethodNode->returnType !== null; - } - - // if not, look for it's parent parent - @todo recursion - } - - if (method_exists($parentClassName, $methodName)) { - // @todo validate type is conflicting - // parent class method in external scope → it's not ok - return true; - - // if not, look for it's parent parent - @todo recursion - } - } - - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classNode instanceof Class_ && ! $classNode instanceof Interface_) { - return false; - } - - $interfaceNames = $this->classManipulator->getClassLikeNodeParentInterfaceNames($classNode); - foreach ($interfaceNames as $interfaceName) { - $interface = $this->parsedNodeCollector->findInterface($interfaceName); - // parent class method in local scope → it's ok - // @todo validate type is conflicting - if ($interface !== null && $interface->getMethod($methodName) !== null) { - return false; - } - - if (method_exists($interfaceName, $methodName)) { - // parent class method in external scope → it's not ok - // @todo validate type is conflicting - return true; - } - } - - return false; + return $this->returnNodeVendorLockResolver->isVendorLocked($classMethod); } public function isPropertyChangeVendorLockedIn(Property $property): bool { + /** @var Class_|null $classNode */ $classNode = $property->getAttribute(AttributeKey::CLASS_NODE); if ($classNode === null) { return false; @@ -189,7 +108,8 @@ public function isPropertyChangeVendorLockedIn(Property $property): bool return false; } - $propertyName = $this->nameResolver->getName($property); + /** @var string|null $propertyName */ + $propertyName = $this->nodeNameResolver->getName($property); if (! is_string($propertyName)) { throw new ShouldNotHappenException(); } @@ -199,18 +119,16 @@ public function isPropertyChangeVendorLockedIn(Property $property): bool $parentClassName = $classNode->getAttribute(AttributeKey::PARENT_CLASS_NAME); if ($parentClassName !== null) { - $parentClassNode = $this->parsedNodeCollector->findClass($parentClassName); - if ($parentClassNode !== null) { - $parentPropertyNode = $this->getProperty($parentClassNode, $propertyName); - // @todo validate type is conflicting - // parent class property in local scope → it's ok - if ($parentPropertyNode !== null) { - return $parentPropertyNode->type !== null; - } + $parentClassProperty = $this->findParentProperty($parentClassName, $propertyName); - // if not, look for it's parent parent - @todo recursion + // @todo validate type is conflicting + // parent class property in local scope → it's ok + if ($parentClassProperty !== null) { + return $parentClassProperty->type !== null; } + // if not, look for it's parent parent - @todo recursion + if (property_exists($parentClassName, $propertyName)) { // @todo validate type is conflicting // parent class property in external scope → it's not ok @@ -233,7 +151,7 @@ public function isPropertyChangeVendorLockedIn(Property $property): bool */ public function isClassMethodRemovalVendorLocked(ClassMethod $classMethod): bool { - $classMethodName = $this->nameResolver->getName($classMethod); + $classMethodName = $this->nodeNameResolver->getName($classMethod); if (! is_string($classMethodName)) { throw new ShouldNotHappenException(); } @@ -244,22 +162,7 @@ public function isClassMethodRemovalVendorLocked(ClassMethod $classMethod): bool return false; } - // required by interface? - foreach ($class->implements as $implement) { - $implementedInterfaceName = $this->nameResolver->getName($implement); - if (! is_string($implementedInterfaceName)) { - throw new ShouldNotHappenException(); - } - - if (! interface_exists($implementedInterfaceName)) { - continue; - } - - $interfaceMethods = get_class_methods($implementedInterfaceName); - if (! in_array($classMethodName, $interfaceMethods, true)) { - continue; - } - + if ($this->isVendorLockedByInterface($class, $classMethodName)) { return true; } @@ -309,15 +212,97 @@ private function hasParentClassOrImplementsInterface(Node $classNode): bool private function getProperty(ClassLike $classLike, string $name) { $lowerName = strtolower($name); - foreach ($classLike->stmts as $stmt) { - if ($stmt instanceof Property) { - foreach ($stmt->props as $prop) { - if ($prop instanceof PropertyProperty && $lowerName === $prop->name->toLowerString()) { - return $stmt; - } + + foreach ($classLike->getProperties() as $property) { + foreach ($property->props as $propertyProperty) { + if ($lowerName !== $propertyProperty->name->toLowerString()) { + continue; } + + return $property; + } + } + + return null; + } + + private function findParentProperty(string $parentClassName, string $propertyName): ?Property + { + $parentClassNode = $this->parsedNodeCollector->findClass($parentClassName); + if ($parentClassNode === null) { + return null; + } + + return $this->getProperty($parentClassNode, $propertyName); + } + + private function isVendorLockedByInterface(Class_ $class, string $classMethodName): bool + { + // required by interface? + foreach ($class->implements as $implement) { + $implementedInterfaceName = $this->nodeNameResolver->getName($implement); + if (! is_string($implementedInterfaceName)) { + throw new ShouldNotHappenException(); + } + + if (! interface_exists($implementedInterfaceName)) { + continue; } + + $interfaceMethods = get_class_methods($implementedInterfaceName); + if (! in_array($classMethodName, $interfaceMethods, true)) { + continue; + } + + return true; + } + + return false; + } + + private function isParentClassVendorLocking(int $paramPosition, string $parentClassName, string $methodName): ?bool + { + $parentClassNode = $this->parsedNodeCollector->findClass($parentClassName); + if ($parentClassNode !== null) { + $parentMethodNode = $parentClassNode->getMethod($methodName); + // @todo validate type is conflicting + // parent class method in local scope → it's ok + if ($parentMethodNode !== null) { + // parent method has no type → we cannot change it here + return isset($parentMethodNode->params[$paramPosition]) && $parentMethodNode->params[$paramPosition]->type === null; + } + } + + // if not, look for it's parent parent - @todo recursion + + if (method_exists($parentClassName, $methodName)) { + // @todo validate type is conflicting + // parent class method in external scope → it's not ok + return true; + + // if not, look for it's parent parent - @todo recursion } + return null; } + + private function isInterfaceParamVendorLockin(array $interfaceNames, string $methodName): bool + { + foreach ($interfaceNames as $interfaceName) { + $interface = $this->parsedNodeCollector->findInterface($interfaceName); + // parent class method in local scope → it's ok + // @todo validate type is conflicting + if ($interface !== null && $interface->getMethod($methodName) !== null) { + return false; + } + + if (method_exists($interfaceName, $methodName)) { + // parent class method in external scope → it's not ok + // @todo validate type is conflicting + return true; + } + } + + return false; + } } diff --git a/packages/zend-to-symfony/src/Detector/ZendDetector.php b/packages/zend-to-symfony/src/Detector/ZendDetector.php index a4171aaf6a91..8cbcf610079e 100644 --- a/packages/zend-to-symfony/src/Detector/ZendDetector.php +++ b/packages/zend-to-symfony/src/Detector/ZendDetector.php @@ -7,7 +7,7 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\ZendToSymfony\ValueObject\ZendClass; @@ -20,14 +20,14 @@ final class ZendDetector private $nodeTypeResolver; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NodeTypeResolver $nodeTypeResolver, NameResolver $nameResolver) + public function __construct(NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver) { $this->nodeTypeResolver = $nodeTypeResolver; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } public function isInZendController(Node $node): bool @@ -50,6 +50,6 @@ public function isZendActionMethod(ClassMethod $classMethod): bool return false; } - return $this->nameResolver->isName($classMethod, '*Action'); + return $this->nodeNameResolver->isName($classMethod, '*Action'); } } diff --git a/packages/zend-to-symfony/src/Rector/ClassMethod/ThisViewToThisRenderResponseRector.php b/packages/zend-to-symfony/src/Rector/ClassMethod/ThisViewToThisRenderResponseRector.php index e4afd4b1488d..53dffca7ec24 100644 --- a/packages/zend-to-symfony/src/Rector/ClassMethod/ThisViewToThisRenderResponseRector.php +++ b/packages/zend-to-symfony/src/Rector/ClassMethod/ThisViewToThisRenderResponseRector.php @@ -58,9 +58,9 @@ public function someAction() { $templateData = []; $templateData['value']; = 5; - + return $this->render("...", $templateData); -} +} PHP )] ); diff --git a/packages/zend-to-symfony/src/Resolver/ControllerMethodParamResolver.php b/packages/zend-to-symfony/src/Resolver/ControllerMethodParamResolver.php index 403438e46485..b2df69471c7a 100644 --- a/packages/zend-to-symfony/src/Resolver/ControllerMethodParamResolver.php +++ b/packages/zend-to-symfony/src/Resolver/ControllerMethodParamResolver.php @@ -10,7 +10,7 @@ use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Exception\NotImplementedException; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -22,14 +22,14 @@ final class ControllerMethodParamResolver private $callableNodeTraverser; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(CallableNodeTraverser $callableNodeTraverser, NameResolver $nameResolver) + public function __construct(CallableNodeTraverser $callableNodeTraverser, NodeNameResolver $nodeNameResolver) { $this->callableNodeTraverser = $callableNodeTraverser; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -45,11 +45,11 @@ public function resolve(ClassMethod $classMethod): array return null; } - if (! $this->nameResolver->isName($node->var, 'this')) { + if (! $this->nodeNameResolver->isName($node->var, 'this')) { return null; } - if (! $this->nameResolver->isName($node->name, 'getParam')) { + if (! $this->nodeNameResolver->isName($node->name, 'getParam')) { return null; } diff --git a/phpstan.neon b/phpstan.neon index 8e1703cf66e1..40a5fef20916 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -240,3 +240,4 @@ parameters: - '#Method Rector\\SOLID\\Reflection\\ParentConstantReflectionResolver\:\:(.*?)\(\) should return ReflectionClassConstant\|null but returns ReflectionClassConstant\|false#' - '#Method Rector\\Core\\NodeContainer\\NodeCollector\\ParsedFunctionLikeNodesByType\:\:findFunction\(\) should return PhpParser\\Node\\Stmt\\Function_\|null but returns PhpParser\\Node\|null#' + - '#Parameter \#1 \$firstStmt of method Rector\\Core\\Rector\\MethodBody\\NormalToFluentRector\:\:isBothMethodCallMatch\(\) expects PhpParser\\Node\\Stmt\\Expression, PhpParser\\Node\\Stmt given#' diff --git a/src/Console/Command/ScreenFileCommand.php b/src/Console/Command/ScreenFileCommand.php index 41dc53263e93..dc4b923e0dc7 100644 --- a/src/Console/Command/ScreenFileCommand.php +++ b/src/Console/Command/ScreenFileCommand.php @@ -19,7 +19,7 @@ use PhpParser\Node\Stmt\Return_; use PHPStan\Type\TypeUtils; use Rector\Core\Console\Shell; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\FileSystemRector\Parser\FileInfoParser; @@ -56,9 +56,9 @@ final class ScreenFileCommand extends AbstractCommand private $callableNodeTraverser; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver @@ -79,7 +79,7 @@ public function __construct( SymfonyStyle $symfonyStyle, FileInfoParser $fileInfoParser, CallableNodeTraverser $callableNodeTraverser, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, BetterStandardPrinter $betterStandardPrinter, StaticTypeMapper $staticTypeMapper @@ -87,7 +87,7 @@ public function __construct( $this->symfonyStyle = $symfonyStyle; $this->fileInfoParser = $fileInfoParser; $this->callableNodeTraverser = $callableNodeTraverser; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; $this->betterStandardPrinter = $betterStandardPrinter; $this->staticTypeMapper = $staticTypeMapper; @@ -172,34 +172,12 @@ private function decorateNodeData(Node $node, array $data = []): array $data = $this->decorateClassLike($node, $data); } - if ($node instanceof Variable) { - $data['name'] = $this->nameResolver->getName($node); - } - if ($node instanceof Assign) { $data = $this->decorateAssign($node, $data); } - if ($node instanceof Namespace_ && $node->name !== null) { - $data['name'] = $this->nameResolver->getName($node->name); - } - - if ($node instanceof FuncCall && $node->name !== null) { - $data['name'] = $this->nameResolver->getName($node->name); - } - - if ($node instanceof Variable) { - $staticType = $this->nodeTypeResolver->getStaticType($node); - - $classNames = TypeUtils::getDirectClassNames($staticType); - if ($classNames !== []) { - $objectTypesAsString = implode(', ', $classNames); - $data['variable_types'] = $objectTypesAsString; - } else { - $typeString = $this->staticTypeMapper->mapPHPStanTypeToDocString($staticType); - $data['variable_types'] = $typeString; - } - } + $data = $this->addNameData($node, $data); + $data = $this->addVariableTypeData($node, $data); if ($node instanceof Return_) { $data = $this->decorateReturn($node, $data); @@ -264,7 +242,7 @@ private function decorateWithNodeType(Node $node, array $data): array */ private function decorateClassLike(ClassLike $classLike, array $data): array { - $data['name'] = $this->nameResolver->getName($classLike); + $data['name'] = $this->nodeNameResolver->getName($classLike); $parentClassName = $classLike->getAttribute(AttributeKey::PARENT_CLASS_NAME); if ($parentClassName) { @@ -318,8 +296,42 @@ private function getObjectShortClass($object): string private function decorateMethodCall(MethodCall $methodCall, array $data): array { $data['method_call_variable'] = $this->decorateNodeData($methodCall->var); - $data['method_call_name'] = $this->nameResolver->getName($methodCall->name); + $data['method_call_name'] = $this->nodeNameResolver->getName($methodCall->name); + + return $data; + } + + private function addNameData(Node $node, array $data): array + { + if ($node instanceof Variable) { + $data['name'] = $this->nodeNameResolver->getName($node); + } + if ($node instanceof Namespace_ && $node->name !== null) { + $data['name'] = $this->nodeNameResolver->getName($node->name); + } + + if ($node instanceof FuncCall && $node->name !== null) { + $data['name'] = $this->nodeNameResolver->getName($node->name); + } + + return $data; + } + + private function addVariableTypeData(Node $node, array $data): array + { + if ($node instanceof Variable) { + $staticType = $this->nodeTypeResolver->getStaticType($node); + + $classNames = TypeUtils::getDirectClassNames($staticType); + if ($classNames !== []) { + $objectTypesAsString = implode(', ', $classNames); + $data['variable_types'] = $objectTypesAsString; + } else { + $typeString = $this->staticTypeMapper->mapPHPStanTypeToDocString($staticType); + $data['variable_types'] = $typeString; + } + } return $data; } } diff --git a/src/Contract/NameResolver/NodeNameResolverInterface.php b/src/Contract/NameResolver/NodeNameResolverInterface.php new file mode 100644 index 000000000000..f560b96a2167 --- /dev/null +++ b/src/Contract/NameResolver/NodeNameResolverInterface.php @@ -0,0 +1,14 @@ +nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -100,7 +100,7 @@ public function collect(Node $node): void } if ($node instanceof Function_) { - $functionName = $this->nameResolver->getName($node); + $functionName = $this->nodeNameResolver->getName($node); if ($functionName === null) { return; } @@ -153,7 +153,7 @@ private function addMethod(ClassMethod $classMethod): void return; } - $methodName = $this->nameResolver->getName($classMethod); + $methodName = $this->nodeNameResolver->getName($classMethod); $this->methodsByType[$className][$methodName] = $classMethod; } @@ -204,17 +204,9 @@ private function matchArrayCallableClassAndMethod(Array_ $array): ?array private function addCall(Node $node): void { // one node can be of multiple-class types - if ($node instanceof MethodCall) { - if ($node->var instanceof MethodCall) { - $classType = $this->resolveNodeClassTypes($node); - } else { - $classType = $this->resolveNodeClassTypes($node->var); - } - } else { - $classType = $this->resolveNodeClassTypes($node->class); - } + $classType = $this->resolveClassType($node); - $methodName = $this->nameResolver->getName($node); + $methodName = $this->nodeNameResolver->getName($node); if ($classType instanceof MixedType) { // anonymous return; } @@ -241,17 +233,17 @@ private function addCall(Node $node): void private function isThisVariable(Node $node): bool { // $this - if ($node instanceof Variable && $this->nameResolver->isName($node, 'this')) { + if ($node instanceof Variable && $this->nodeNameResolver->isName($node, 'this')) { return true; } if ($node instanceof ClassConstFetch) { - if (! $this->nameResolver->isName($node->name, 'class')) { + if (! $this->nodeNameResolver->isName($node->name, 'class')) { return false; } // self::class, static::class - if ($this->nameResolver->isNames($node->class, ['self', 'static'])) { + if ($this->nodeNameResolver->isNames($node->class, ['self', 'static'])) { return true; } @@ -262,7 +254,7 @@ private function isThisVariable(Node $node): bool return false; } - return $this->nameResolver->isName($node->class, $className); + return $this->nodeNameResolver->isName($node->class, $className); } return false; @@ -287,4 +279,20 @@ private function resolveNodeClassTypes(Node $node): Type return $this->nodeTypeResolver->resolve($node); } + + /** + * @param MethodCall|StaticCall $node + */ + private function resolveClassType(Node $node): Type + { + if ($node instanceof MethodCall) { + if ($node->var instanceof MethodCall) { + return $this->resolveNodeClassTypes($node); + } + + return $this->resolveNodeClassTypes($node->var); + } + + return $this->resolveNodeClassTypes($node->class); + } } diff --git a/src/NodeContainer/NodeCollector/ParsedNodeCollector.php b/src/NodeContainer/NodeCollector/ParsedNodeCollector.php index 29837adfdc91..b165e301abfa 100644 --- a/src/NodeContainer/NodeCollector/ParsedNodeCollector.php +++ b/src/NodeContainer/NodeCollector/ParsedNodeCollector.php @@ -20,7 +20,7 @@ use PhpParser\Node\Stmt\Trait_; use Rector\Core\Exception\NotImplementedException; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; /** @@ -64,9 +64,9 @@ final class ParsedNodeCollector private $simpleParsedNodesByType = []; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var Interface_[] @@ -78,9 +78,9 @@ final class ParsedNodeCollector */ private $traits = []; - public function __construct(NameResolver $nameResolver) + public function __construct(NodeNameResolver $nodeNameResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -182,7 +182,7 @@ public function collect(Node $node): void } if ($node instanceof Interface_ || $node instanceof Trait_) { - $name = $this->nameResolver->getName($node); + $name = $this->nodeNameResolver->getName($node); if ($name === null) { throw new ShouldNotHappenException(); } @@ -216,7 +216,7 @@ public function findNewNodesByClass(string $className): array $news = $this->getNodesByType(New_::class); foreach ($news as $new) { - if (! $this->nameResolver->isName($new->class, $className)) { + if (! $this->nodeNameResolver->isName($new->class, $className)) { continue; } @@ -228,7 +228,7 @@ public function findNewNodesByClass(string $className): array public function findClassConstantByClassConstFetch(ClassConstFetch $classConstFetch): ?ClassConst { - $class = $this->nameResolver->getName($classConstFetch->class); + $class = $this->nodeNameResolver->getName($classConstFetch->class); if ($class === 'self') { /** @var string|null $class */ @@ -243,7 +243,7 @@ public function findClassConstantByClassConstFetch(ClassConstFetch $classConstFe } /** @var string $constantName */ - $constantName = $this->nameResolver->getName($classConstFetch->name); + $constantName = $this->nodeNameResolver->getName($classConstFetch->name); return $this->findClassConstant($class, $constantName); } @@ -270,7 +270,7 @@ private function addClassConstant(ClassConst $classConst): void return; } - $constantName = $this->nameResolver->getName($classConst); + $constantName = $this->nodeNameResolver->getName($classConst); $this->constantsByType[$className][$constantName] = $classConst; } diff --git a/src/NodeContainer/NodeFinder/ClassLikeParsedNodesFinder.php b/src/NodeContainer/NodeFinder/ClassLikeParsedNodesFinder.php index 2dd278096639..093b2c07ffbc 100644 --- a/src/NodeContainer/NodeFinder/ClassLikeParsedNodesFinder.php +++ b/src/NodeContainer/NodeFinder/ClassLikeParsedNodesFinder.php @@ -10,7 +10,7 @@ use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Trait_; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; final class ClassLikeParsedNodesFinder @@ -21,14 +21,14 @@ final class ClassLikeParsedNodesFinder private $parsedNodeCollector; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(ParsedNodeCollector $parsedNodeCollector, NameResolver $nameResolver) + public function __construct(ParsedNodeCollector $parsedNodeCollector, NodeNameResolver $nodeNameResolver) { $this->parsedNodeCollector = $parsedNodeCollector; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -82,7 +82,7 @@ public function findUsedTraitsInClass(ClassLike $classLike): array foreach ($classLike->getTraitUses() as $traitUse) { foreach ($traitUse->traits as $trait) { - $traitName = $this->nameResolver->getName($trait); + $traitName = $this->nodeNameResolver->getName($trait); if ($traitName === null) { continue; } diff --git a/src/NodeContainer/NodeFinder/FunctionLikeParsedNodesFinder.php b/src/NodeContainer/NodeFinder/FunctionLikeParsedNodesFinder.php index fe4f61872d71..dd0438cfb017 100644 --- a/src/NodeContainer/NodeFinder/FunctionLikeParsedNodesFinder.php +++ b/src/NodeContainer/NodeFinder/FunctionLikeParsedNodesFinder.php @@ -12,7 +12,7 @@ use PhpParser\Node\Stmt\Function_; use PHPStan\Type\TypeUtils; use Rector\Core\NodeContainer\NodeCollector\ParsedFunctionLikeNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use ReflectionClass; @@ -20,9 +20,9 @@ final class FunctionLikeParsedNodesFinder { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeTypeResolver @@ -35,11 +35,11 @@ final class FunctionLikeParsedNodesFinder private $parsedFunctionLikeNodeCollector; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, ParsedFunctionLikeNodeCollector $parsedFunctionLikeNodeCollector ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; $this->parsedFunctionLikeNodeCollector = $parsedFunctionLikeNodeCollector; } @@ -52,7 +52,7 @@ public function findClassMethodByMethodCall(MethodCall $methodCall): ?ClassMetho return null; } - $methodName = $this->nameResolver->getName($methodCall->name); + $methodName = $this->nodeNameResolver->getName($methodCall->name); if ($methodName === null) { return null; } @@ -62,7 +62,7 @@ public function findClassMethodByMethodCall(MethodCall $methodCall): ?ClassMetho public function findClassMethodByStaticCall(StaticCall $staticCall): ?ClassMethod { - $methodName = $this->nameResolver->getName($staticCall->name); + $methodName = $this->nodeNameResolver->getName($staticCall->name); if ($methodName === null) { return null; } @@ -135,7 +135,7 @@ public function findClassMethodCalls(ClassMethod $classMethod): array } /** @var string|null $methodName */ - $methodName = $this->nameResolver->getName($classMethod); + $methodName = $this->nodeNameResolver->getName($classMethod); if ($methodName === null) { return []; } diff --git a/src/PHPStan/Reflection/CallReflectionResolver.php b/src/PHPStan/Reflection/CallReflectionResolver.php index 046f52e256ef..952b8b684de2 100644 --- a/src/PHPStan/Reflection/CallReflectionResolver.php +++ b/src/PHPStan/Reflection/CallReflectionResolver.php @@ -25,7 +25,7 @@ use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ObjectType; use PHPStan\Type\ObjectWithoutClassType; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -51,18 +51,18 @@ final class CallReflectionResolver private $nodeTypeResolver; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; public function __construct( ReflectionProvider $reflectionProvider, NodeTypeResolver $nodeTypeResolver, - NameResolver $nameResolver + NodeNameResolver $nodeNameResolver ) { $this->reflectionProvider = $reflectionProvider; $this->nodeTypeResolver = $nodeTypeResolver; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -132,7 +132,7 @@ public function resolveMethodCall(Node $node): ?MethodReflection } $classType = $this->nodeTypeResolver->resolve($node instanceof MethodCall ? $node->var : $node->class); - $methodName = $this->nameResolver->getName($node->name); + $methodName = $this->nodeNameResolver->getName($node->name); if ($methodName === null || ! $classType->hasMethod($methodName)->yes()) { return null; diff --git a/src/Php/Regex/RegexPatternArgumentManipulator.php b/src/Php/Regex/RegexPatternArgumentManipulator.php index 10c0a704d5a0..3bbb56067c9d 100644 --- a/src/Php/Regex/RegexPatternArgumentManipulator.php +++ b/src/Php/Regex/RegexPatternArgumentManipulator.php @@ -15,7 +15,7 @@ use PhpParser\Node\Scalar\String_; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -53,9 +53,9 @@ final class RegexPatternArgumentManipulator private $nodeTypeResolver; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BetterNodeFinder @@ -74,13 +74,13 @@ final class RegexPatternArgumentManipulator public function __construct( NodeTypeResolver $nodeTypeResolver, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ParsedNodeCollector $parsedNodeCollector, BetterNodeFinder $betterNodeFinder, BetterStandardPrinter $betterStandardPrinter ) { $this->nodeTypeResolver = $nodeTypeResolver; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parsedNodeCollector = $parsedNodeCollector; $this->betterNodeFinder = $betterNodeFinder; $this->betterStandardPrinter = $betterStandardPrinter; @@ -108,7 +108,7 @@ public function matchCallArgumentWithRegexPattern(Expr $expr): array private function processFuncCall(FuncCall $funcCall): array { foreach ($this->functionsWithPatternsToArgumentPosition as $functionName => $argumentPosition) { - if (! $this->nameResolver->isName($funcCall, $functionName)) { + if (! $this->nodeNameResolver->isName($funcCall, $functionName)) { continue; } @@ -133,7 +133,7 @@ private function processStaticCall(StaticCall $staticCall): array } foreach ($methodNamesToArgumentPosition as $methodName => $argumentPosition) { - if (! $this->nameResolver->isName($staticCall, $methodName)) { + if (! $this->nodeNameResolver->isName($staticCall, $methodName)) { continue; } diff --git a/src/PhpParser/Node/Manipulator/AssignManipulator.php b/src/PhpParser/Node/Manipulator/AssignManipulator.php index 1978b056855d..98b42286e267 100644 --- a/src/PhpParser/Node/Manipulator/AssignManipulator.php +++ b/src/PhpParser/Node/Manipulator/AssignManipulator.php @@ -10,24 +10,24 @@ use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\List_; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; final class AssignManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var PropertyFetchManipulator */ private $propertyFetchManipulator; - public function __construct(NameResolver $nameResolver, PropertyFetchManipulator $propertyFetchManipulator) + public function __construct(NodeNameResolver $nodeNameResolver, PropertyFetchManipulator $propertyFetchManipulator) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->propertyFetchManipulator = $propertyFetchManipulator; } @@ -62,7 +62,7 @@ public function isLocalPropertyAssignWithPropertyNames(Node $node, array $proper return false; } - return $this->nameResolver->isNames($propertyFetch, $propertyNames); + return $this->nodeNameResolver->isNames($propertyFetch, $propertyNames); } /** @@ -95,7 +95,7 @@ public function isListToEachAssign(Assign $assign): bool return false; } - return $this->nameResolver->isName($assign->expr, 'each'); + return $this->nodeNameResolver->isName($assign->expr, 'each'); } public function isNodeLeftPartOfAssign(Node $node): bool diff --git a/src/PhpParser/Node/Manipulator/ChainMethodCallManipulator.php b/src/PhpParser/Node/Manipulator/ChainMethodCallManipulator.php index d739b7deb8c0..139b5e9aed1f 100644 --- a/src/PhpParser/Node/Manipulator/ChainMethodCallManipulator.php +++ b/src/PhpParser/Node/Manipulator/ChainMethodCallManipulator.php @@ -8,7 +8,7 @@ use PhpParser\Node\Expr\MethodCall; use PHPStan\Type\MixedType; use PHPStan\Type\Type; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\NodeTypeResolver; /** @@ -23,14 +23,14 @@ final class ChainMethodCallManipulator private $nodeTypeResolver; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NodeTypeResolver $nodeTypeResolver, NameResolver $nameResolver) + public function __construct(NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver) { $this->nodeTypeResolver = $nodeTypeResolver; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -48,7 +48,7 @@ public function isTypeAndChainCalls(Node $node, Type $type, array $methods): boo $methods = array_reverse($methods); foreach ($methods as $method) { - $activeMethodName = $this->nameResolver->getName($node); + $activeMethodName = $this->nodeNameResolver->getName($node); if ($activeMethodName !== $method) { return false; } diff --git a/src/PhpParser/Node/Manipulator/ChildAndParentClassManipulator.php b/src/PhpParser/Node/Manipulator/ChildAndParentClassManipulator.php index f31e3c32128f..68beeaceb207 100644 --- a/src/PhpParser/Node/Manipulator/ChildAndParentClassManipulator.php +++ b/src/PhpParser/Node/Manipulator/ChildAndParentClassManipulator.php @@ -10,7 +10,7 @@ use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; use Rector\Core\NodeContainer\NodeFinder\ClassLikeParsedNodesFinder; use Rector\Core\PhpParser\Node\NodeFactory; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; final class ChildAndParentClassManipulator @@ -21,9 +21,9 @@ final class ChildAndParentClassManipulator private $nodeFactory; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ClassLikeParsedNodesFinder @@ -38,11 +38,11 @@ final class ChildAndParentClassManipulator public function __construct( ParsedNodeCollector $parsedNodeCollector, NodeFactory $nodeFactory, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ClassLikeParsedNodesFinder $classLikeParsedNodesFinder ) { $this->nodeFactory = $nodeFactory; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->classLikeParsedNodesFinder = $classLikeParsedNodesFinder; $this->parsedNodeCollector = $parsedNodeCollector; } @@ -75,7 +75,7 @@ public function completeParentConstructor(Class_ $classNode, ClassMethod $classM public function completeChildConstructors(Class_ $classNode, ClassMethod $constructorClassMethod): void { - $className = $this->nameResolver->getName($classNode); + $className = $this->nodeNameResolver->getName($classNode); if ($className === null) { return; } diff --git a/src/PhpParser/Node/Manipulator/ClassConstManipulator.php b/src/PhpParser/Node/Manipulator/ClassConstManipulator.php index a8a93f5233c0..55073650d60c 100644 --- a/src/PhpParser/Node/Manipulator/ClassConstManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassConstManipulator.php @@ -10,16 +10,16 @@ use PhpParser\Node\Stmt\ClassConst; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\Node\AttributeKey; final class ClassConstManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var BetterNodeFinder @@ -42,13 +42,13 @@ final class ClassConstManipulator private $classManipulator; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, BetterStandardPrinter $betterStandardPrinter, ParsedNodeCollector $parsedNodeCollector, ClassManipulator $classManipulator ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->betterNodeFinder = $betterNodeFinder; $this->betterStandardPrinter = $betterStandardPrinter; $this->parsedNodeCollector = $parsedNodeCollector; @@ -98,7 +98,7 @@ public function getAllClassConstFetch(ClassConst $classConst): array private function isNameMatch(Node $node, ClassConst $classConst): bool { - return $this->nameResolver->getName($node) === 'self::' . $this->nameResolver->getName($classConst) - || $this->nameResolver->getName($node) === 'static::' . $this->nameResolver->getName($classConst); + return $this->nodeNameResolver->getName($node) === 'self::' . $this->nodeNameResolver->getName($classConst) + || $this->nodeNameResolver->getName($node) === 'static::' . $this->nodeNameResolver->getName($classConst); } } diff --git a/src/PhpParser/Node/Manipulator/ClassManipulator.php b/src/PhpParser/Node/Manipulator/ClassManipulator.php index c27b00174439..a1bdd1e9ea83 100644 --- a/src/PhpParser/Node/Manipulator/ClassManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassManipulator.php @@ -26,7 +26,7 @@ use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\PhpParser\Node\Commander\NodeRemovingCommander; use Rector\Core\PhpParser\Node\NodeFactory; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -35,9 +35,9 @@ final class ClassManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var NodeFactory @@ -70,7 +70,7 @@ final class ClassManipulator private $nodeTypeResolver; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, NodeFactory $nodeFactory, ChildAndParentClassManipulator $childAndParentClassManipulator, CallableNodeTraverser $callableNodeTraverser, @@ -79,7 +79,7 @@ public function __construct( NodeTypeResolver $nodeTypeResolver ) { $this->nodeFactory = $nodeFactory; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->childAndParentClassManipulator = $childAndParentClassManipulator; $this->callableNodeTraverser = $callableNodeTraverser; $this->nodeRemovingCommander = $nodeRemovingCommander; @@ -190,7 +190,7 @@ public function getUsedTraits(ClassLike $classLike): array $usedTraits = []; foreach ($classLike->getTraitUses() as $stmt) { foreach ($stmt->traits as $trait) { - $traitName = $this->nameResolver->getName($trait); + $traitName = $this->nodeNameResolver->getName($trait); if ($traitName !== null) { $usedTraits[$traitName] = $trait; } @@ -208,7 +208,7 @@ public function getProperty(ClassLike $classLike, string $name): ?Property throw new ShouldNotHappenException(); } - if ($this->nameResolver->isName($property, $name)) { + if ($this->nodeNameResolver->isName($property, $name)) { return $property; } } @@ -254,7 +254,7 @@ public function removeProperty(Class_ $class, string $propertyName): void public function findMethodParamByName(ClassMethod $classMethod, string $name): ?Param { foreach ($classMethod->params as $param) { - if (! $this->nameResolver->isName($param, $name)) { + if (! $this->nodeNameResolver->isName($param, $name)) { continue; } @@ -276,7 +276,7 @@ public function getPrivatePropertyNames(Class_ $class): array } /** @var string $propertyName */ - $propertyName = $this->nameResolver->getName($property); + $propertyName = $this->nodeNameResolver->getName($property); $privatePropertyNames[] = $propertyName; } @@ -299,7 +299,7 @@ public function getPublicMethodNames(Class_ $class): array } /** @var string $methodName */ - $methodName = $this->nameResolver->getName($method); + $methodName = $this->nodeNameResolver->getName($method); $publicMethodNames[] = $methodName; } @@ -316,7 +316,7 @@ public function removeProperties(Class_ $class, array $propertyNames): void return null; } - if (! $this->nameResolver->isNames($node, $propertyNames)) { + if (! $this->nodeNameResolver->isNames($node, $propertyNames)) { return null; } @@ -376,7 +376,7 @@ public function getImplementedInterfaceNames(Class_ $class): array $implementedInterfaceNames = []; foreach ($class->implements as $implement) { - $interfaceName = $this->nameResolver->getName($implement); + $interfaceName = $this->nodeNameResolver->getName($implement); if (! is_string($interfaceName)) { throw new ShouldNotHappenException(); } @@ -391,7 +391,7 @@ public function hasPropertyName(Class_ $node, string $name): bool { foreach ($node->getProperties() as $property) { foreach ($property->props as $propertyProperty) { - if (! $this->nameResolver->isName($propertyProperty, $name)) { + if (! $this->nodeNameResolver->isName($propertyProperty, $name)) { continue; } @@ -406,7 +406,7 @@ public function hasClassTrait(Class_ $class, string $desiredTrait): bool { foreach ($class->getTraitUses() as $traitUse) { foreach ($traitUse->traits as $traitTrait) { - if (! $this->nameResolver->isName($traitTrait, $desiredTrait)) { + if (! $this->nodeNameResolver->isName($traitTrait, $desiredTrait)) { continue; } @@ -421,7 +421,7 @@ public function replaceTrait(Class_ $class, string $oldTrait, string $newTrait): { foreach ($class->getTraitUses() as $traitUse) { foreach ($traitUse->traits as $key => $traitTrait) { - if (! $this->nameResolver->isName($traitTrait, $oldTrait)) { + if (! $this->nodeNameResolver->isName($traitTrait, $oldTrait)) { continue; } @@ -451,7 +451,7 @@ public function getClassLikeNodeParentInterfaceNames(ClassLike $classLike) public function hasInterface(Class_ $class, string $desiredInterface): bool { foreach ($class->implements as $implement) { - if (! $this->nameResolver->isName($implement, $desiredInterface)) { + if (! $this->nodeNameResolver->isName($implement, $desiredInterface)) { continue; } @@ -464,7 +464,7 @@ public function hasInterface(Class_ $class, string $desiredInterface): bool public function removeInterface(Class_ $class, string $desiredInterface): void { foreach ($class->implements as $implement) { - if (! $this->nameResolver->isName($implement, $desiredInterface)) { + if (! $this->nodeNameResolver->isName($implement, $desiredInterface)) { continue; } @@ -484,12 +484,12 @@ public function renamePropertyFetches(Class_ $class, array $oldToNewPropertyName return null; } - if (! $this->nameResolver->isName($node->var, 'this')) { + if (! $this->nodeNameResolver->isName($node->var, 'this')) { return null; } foreach ($oldToNewPropertyNames as $oldPropertyName => $newPropertyName) { - if (! $this->nameResolver->isName($node->name, $oldPropertyName)) { + if (! $this->nodeNameResolver->isName($node->name, $oldPropertyName)) { continue; } @@ -549,7 +549,7 @@ private function addStatementToClassBeforeTypes(Class_ $classNode, Stmt $stmt, s private function hasClassProperty(Class_ $classNode, string $name): bool { foreach ($classNode->getProperties() as $property) { - if ($this->nameResolver->isName($property, $name)) { + if ($this->nodeNameResolver->isName($property, $name)) { return true; } } @@ -578,7 +578,7 @@ private function getClassMethodNames(Class_ $classNode): array { $classMethodNames = []; foreach ($classNode->getMethods() as $classMethod) { - $methodName = $this->nameResolver->getName($classMethod); + $methodName = $this->nodeNameResolver->getName($classMethod); if (! is_string($methodName)) { throw new ShouldNotHappenException(); } @@ -637,7 +637,7 @@ private function getClassImplementedInterfaceNames(Class_ $class): array $interfaceNames = []; foreach ($class->implements as $implementNode) { - $interfaceName = $this->nameResolver->getName($implementNode); + $interfaceName = $this->nodeNameResolver->getName($implementNode); if ($interfaceName === null) { continue; } @@ -656,7 +656,7 @@ private function getInterfaceExtendedInterfacesNames(Interface_ $interface): arr $interfaceNames = []; foreach ($interface->extends as $extendNode) { - $interfaceName = $this->nameResolver->getName($extendNode); + $interfaceName = $this->nodeNameResolver->getName($extendNode); if ($interfaceName === null) { continue; } @@ -670,7 +670,7 @@ private function getInterfaceExtendedInterfacesNames(Interface_ $interface): arr private function hasMethodParameter(ClassMethod $classMethod, string $name): bool { foreach ($classMethod->params as $constructorParameter) { - if ($this->nameResolver->isName($constructorParameter->var, $name)) { + if ($this->nodeNameResolver->isName($constructorParameter->var, $name)) { return true; } } diff --git a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php index 6a71596979c4..4cf1a2897b68 100644 --- a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php @@ -13,7 +13,7 @@ use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -37,9 +37,9 @@ final class ClassMethodManipulator private $nodeTypeResolver; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ValueResolver @@ -50,13 +50,13 @@ public function __construct( BetterNodeFinder $betterNodeFinder, BetterStandardPrinter $betterStandardPrinter, NodeTypeResolver $nodeTypeResolver, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, ValueResolver $valueResolver ) { $this->betterNodeFinder = $betterNodeFinder; $this->betterStandardPrinter = $betterStandardPrinter; $this->nodeTypeResolver = $nodeTypeResolver; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->valueResolver = $valueResolver; } @@ -78,17 +78,17 @@ public function isParameterUsedMethod(Param $param, ClassMethod $classMethod): b return false; } - return $this->nameResolver->isName($node, 'compact'); + return $this->nodeNameResolver->isName($node, 'compact'); }); $arguments = $this->extractArgumentsFromCompactFuncCalls($compactFuncCalls); - return $this->nameResolver->isNames($param, $arguments); + return $this->nodeNameResolver->isNames($param, $arguments); } public function isNamedConstructor(ClassMethod $classMethod): bool { - if (! $this->nameResolver->isName($classMethod, '__construct')) { + if (! $this->nodeNameResolver->isName($classMethod, '__construct')) { return false; } @@ -102,7 +102,7 @@ public function isNamedConstructor(ClassMethod $classMethod): bool public function hasParentMethodOrInterfaceMethod(ClassMethod $classMethod, ?string $methodName = null): bool { - $methodName = $methodName ?? $this->nameResolver->getName($classMethod->name); + $methodName = $methodName ?? $this->nodeNameResolver->getName($classMethod->name); $class = $classMethod->getAttribute(AttributeKey::CLASS_NAME); if (! is_string($class)) { @@ -141,7 +141,7 @@ public function isStaticClassMethod(ClassMethod $classMethod): bool return false; } - return $this->nameResolver->isName($node, 'this'); + return $this->nodeNameResolver->isName($node, 'this'); }); } @@ -161,7 +161,7 @@ public function addMethodParameterIfMissing(Node $node, string $type, array $pos continue; } - $paramName = $this->nameResolver->getName($paramNode); + $paramName = $this->nodeNameResolver->getName($paramNode); if (! is_string($paramName)) { throw new ShouldNotHappenException(); } @@ -178,7 +178,7 @@ public function addMethodParameterIfMissing(Node $node, string $type, array $pos public function removeParameter(Param $param, ClassMethod $classMethod): void { foreach ($classMethod->params as $key => $constructorParam) { - if (! $this->nameResolver->areNamesEqual($constructorParam, $param)) { + if (! $this->nodeNameResolver->areNamesEqual($constructorParam, $param)) { continue; } @@ -233,7 +233,7 @@ private function resolveName(ClassMethod $classMethod, array $possibleNames): st { foreach ($possibleNames as $possibleName) { foreach ($classMethod->params as $paramNode) { - if ($this->nameResolver->isName($paramNode, $possibleName)) { + if ($this->nodeNameResolver->isName($paramNode, $possibleName)) { continue 2; } } diff --git a/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php b/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php index a105d151874c..9450a92756d7 100644 --- a/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php +++ b/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php @@ -8,15 +8,15 @@ use PhpParser\Node\FunctionLike; use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Return_; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; final class FunctionLikeManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser @@ -29,11 +29,11 @@ final class FunctionLikeManipulator private $propertyFetchManipulator; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser, PropertyFetchManipulator $propertyFetchManipulator ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; $this->propertyFetchManipulator = $propertyFetchManipulator; } @@ -60,7 +60,7 @@ public function getReturnedLocalPropertyNames(FunctionLike $functionLike): array return null; } - $propertyName = $this->nameResolver->getName($node->expr); + $propertyName = $this->nodeNameResolver->getName($node->expr); if ($propertyName === null) { return null; } diff --git a/src/PhpParser/Node/Manipulator/IdentifierManipulator.php b/src/PhpParser/Node/Manipulator/IdentifierManipulator.php index e9ac124a8735..35ee599cffdb 100644 --- a/src/PhpParser/Node/Manipulator/IdentifierManipulator.php +++ b/src/PhpParser/Node/Manipulator/IdentifierManipulator.php @@ -13,7 +13,7 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Exception\NodeChanger\NodeMissingIdentifierException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; /** * This class renames node identifier, e.g. ClassMethod rename: @@ -31,13 +31,13 @@ final class IdentifierManipulator ]; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NameResolver $nameResolver) + public function __construct(NodeNameResolver $nodeNameResolver) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -48,7 +48,7 @@ public function renameNodeWithMap(Node $node, array $renameMethodMap): void { $this->ensureNodeHasIdentifier($node); - $oldNodeMethodName = $this->nameResolver->getName($node); + $oldNodeMethodName = $this->nodeNameResolver->getName($node); if ($oldNodeMethodName === null) { return; } @@ -63,7 +63,7 @@ public function removeSuffix(Node $node, string $suffixToRemove): void { $this->ensureNodeHasIdentifier($node); - $name = $this->nameResolver->getName($node); + $name = $this->nodeNameResolver->getName($node); if ($name === null) { return; } diff --git a/src/PhpParser/Node/Manipulator/IfManipulator.php b/src/PhpParser/Node/Manipulator/IfManipulator.php index 2e61010b0356..e39f88db3be4 100644 --- a/src/PhpParser/Node/Manipulator/IfManipulator.php +++ b/src/PhpParser/Node/Manipulator/IfManipulator.php @@ -13,7 +13,7 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\Return_; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; final class IfManipulator @@ -34,20 +34,20 @@ final class IfManipulator private $stmtsManipulator; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; public function __construct( BetterStandardPrinter $betterStandardPrinter, ConstFetchManipulator $constFetchManipulator, StmtsManipulator $stmtsManipulator, - NameResolver $nameResolver + NodeNameResolver $nodeNameResolver ) { $this->betterStandardPrinter = $betterStandardPrinter; $this->constFetchManipulator = $constFetchManipulator; $this->stmtsManipulator = $stmtsManipulator; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -213,7 +213,7 @@ public function isIfOrIfElseWithFunctionCondition(If_ $if, string $functionName) if (! $if->cond instanceof FuncCall) { return false; } - return $this->nameResolver->isName($if->cond, $functionName); + return $this->nodeNameResolver->isName($if->cond, $functionName); } private function matchComparedAndReturnedNode(NotIdentical $notIdentical, Return_ $returnNode): ?Expr diff --git a/src/PhpParser/Node/Manipulator/MethodCallManipulator.php b/src/PhpParser/Node/Manipulator/MethodCallManipulator.php index d61f00fefd19..d4a9af51cafd 100644 --- a/src/PhpParser/Node/Manipulator/MethodCallManipulator.php +++ b/src/PhpParser/Node/Manipulator/MethodCallManipulator.php @@ -11,16 +11,16 @@ use PhpParser\Node\FunctionLike; use PhpParser\Node\Stmt\Expression; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\Node\AttributeKey; final class MethodCallManipulator { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser @@ -33,11 +33,11 @@ final class MethodCallManipulator private $betterNodeFinder; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser, BetterNodeFinder $betterNodeFinder ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; $this->betterNodeFinder = $betterNodeFinder; } @@ -51,7 +51,7 @@ public function findMethodCallNamesOnVariable(Variable $variable): array $methodCallNamesOnVariable = []; foreach ($methodCallsOnVariable as $methodCallOnVariable) { - $methodName = $this->nameResolver->getName($methodCallOnVariable); + $methodName = $this->nodeNameResolver->getName($methodCallOnVariable); if ($methodName === null) { continue; } @@ -95,7 +95,7 @@ public function findAssignToVariable(Variable $variable): ?Assign return null; } - $variableName = $this->nameResolver->getName($variable); + $variableName = $this->nodeNameResolver->getName($variable); if ($variableName === null) { return null; } @@ -123,7 +123,7 @@ private function findMethodCallsOnVariable(Variable $variable): array return []; } - $variableName = $this->nameResolver->getName($variable); + $variableName = $this->nodeNameResolver->getName($variable); if ($variableName === null) { return []; } @@ -176,7 +176,7 @@ private function findAssignToVariableName(Node $node, string $variableName): ?As return false; } - return $this->nameResolver->isName($node->var, $variableName); + return $this->nodeNameResolver->isName($node->var, $variableName); }); return $assign; @@ -217,7 +217,7 @@ private function collectMethodCallsOnVariableName(Node $node, string $variableNa return null; } - if (! $this->nameResolver->isName($node->var, $variableName)) { + if (! $this->nodeNameResolver->isName($node->var, $variableName)) { return null; } diff --git a/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php b/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php index 6c21c66693ff..31da5218cfc2 100644 --- a/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php +++ b/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php @@ -20,7 +20,7 @@ use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -42,9 +42,9 @@ final class PropertyFetchManipulator private $reflectionProvider; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var CallableNodeTraverser @@ -54,18 +54,18 @@ final class PropertyFetchManipulator public function __construct( NodeTypeResolver $nodeTypeResolver, ReflectionProvider $reflectionProvider, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser ) { $this->nodeTypeResolver = $nodeTypeResolver; $this->reflectionProvider = $reflectionProvider; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->callableNodeTraverser = $callableNodeTraverser; } public function isPropertyToSelf(PropertyFetch $propertyFetch): bool { - if (! $this->nameResolver->isName($propertyFetch->var, 'this')) { + if (! $this->nodeNameResolver->isName($propertyFetch->var, 'this')) { return false; } @@ -75,12 +75,12 @@ public function isPropertyToSelf(PropertyFetch $propertyFetch): bool return false; } - if (! $this->nameResolver->isName($propertyFetch->var, 'this')) { + if (! $this->nodeNameResolver->isName($propertyFetch->var, 'this')) { return false; } foreach ($class->getProperties() as $property) { - if ($this->nameResolver->areNamesEqual($property->props[0], $propertyFetch)) { + if ($this->nodeNameResolver->areNamesEqual($property->props[0], $propertyFetch)) { return true; } } @@ -108,7 +108,7 @@ public function isMagicOnType(Node $node, Type $type): bool return false; } - $nodeName = $this->nameResolver->getName($node); + $nodeName = $this->nodeNameResolver->getName($node); if ($nodeName === null) { return false; } @@ -132,7 +132,7 @@ public function getPropertyNamesOfAssignOfVariable(Node $node, string $paramName } /** @var Assign $node */ - $propertyName = $this->nameResolver->getName($node->expr); + $propertyName = $this->nodeNameResolver->getName($node->expr); if ($propertyName) { $propertyNames[] = $propertyName; } @@ -157,7 +157,7 @@ public function isVariableAssignToThisPropertyFetch(Node $node, string $variable return false; } - if (! $this->nameResolver->isName($node->expr, $variableName)) { + if (! $this->nodeNameResolver->isName($node->expr, $variableName)) { return false; } @@ -165,7 +165,7 @@ public function isVariableAssignToThisPropertyFetch(Node $node, string $variable return false; } // must be local property - return $this->nameResolver->isName($node->var->var, 'this'); + return $this->nodeNameResolver->isName($node->var->var, 'this'); } /** @@ -178,7 +178,7 @@ public function isLocalPropertyOfNames(Node $node, array $propertyNames): bool } /** @var PropertyFetch $node */ - return $this->nameResolver->isNames($node->name, $propertyNames); + return $this->nodeNameResolver->isNames($node->name, $propertyNames); } public function isLocalProperty(Node $node): bool @@ -187,7 +187,7 @@ public function isLocalProperty(Node $node): bool return false; } - return $this->nameResolver->isName($node->var, 'this'); + return $this->nodeNameResolver->isName($node->var, 'this'); } /** @@ -211,11 +211,11 @@ public function resolveParamForPropertyFetch(ClassMethod $classMethod, string $p return null; } - if (! $this->nameResolver->isName($node->var, $propertyName)) { + if (! $this->nodeNameResolver->isName($node->var, $propertyName)) { return null; } - $assignedParamName = $this->nameResolver->getName($node->expr); + $assignedParamName = $this->nodeNameResolver->getName($node->expr); return NodeTraverser::STOP_TRAVERSAL; }); @@ -227,7 +227,7 @@ public function resolveParamForPropertyFetch(ClassMethod $classMethod, string $p /** @var Param $param */ foreach ((array) $classMethod->params as $param) { - if (! $this->nameResolver->isName($param, $assignedParamName)) { + if (! $this->nodeNameResolver->isName($param, $assignedParamName)) { continue; } @@ -277,11 +277,11 @@ public function isToThisPropertyFetchOfSpecificNameAssign(Node $node, string $pr return false; } - if (! $this->nameResolver->isName($node->var->var, 'this')) { + if (! $this->nodeNameResolver->isName($node->var->var, 'this')) { return false; } - return $this->nameResolver->isName($node->var->name, $propertyName); + return $this->nodeNameResolver->isName($node->var->name, $propertyName); } private function hasPublicProperty(PropertyFetch $propertyFetch, string $propertyName): bool diff --git a/src/PhpParser/Node/Manipulator/PropertyManipulator.php b/src/PhpParser/Node/Manipulator/PropertyManipulator.php index 4f35f8ba253a..9f6adc0aafc8 100644 --- a/src/PhpParser/Node/Manipulator/PropertyManipulator.php +++ b/src/PhpParser/Node/Manipulator/PropertyManipulator.php @@ -17,7 +17,7 @@ use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\NodeContainer\NodeFinder\ClassLikeParsedNodesFinder; use Rector\Core\PhpParser\Node\BetterNodeFinder; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\Core\PhpParser\Printer\BetterStandardPrinter; use Rector\Doctrine\AbstractRector\DoctrineTrait; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -40,9 +40,9 @@ final class PropertyManipulator private $betterStandardPrinter; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var AssignManipulator @@ -57,13 +57,13 @@ final class PropertyManipulator public function __construct( BetterNodeFinder $betterNodeFinder, BetterStandardPrinter $betterStandardPrinter, - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, AssignManipulator $assignManipulator, ClassLikeParsedNodesFinder $classLikeParsedNodesFinder ) { $this->betterNodeFinder = $betterNodeFinder; $this->betterStandardPrinter = $betterStandardPrinter; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->assignManipulator = $assignManipulator; $this->classLikeParsedNodesFinder = $classLikeParsedNodesFinder; } @@ -98,7 +98,7 @@ public function getAllPropertyFetch(PropertyProperty $propertyProperty): array } // is it the name match? - if (! $this->nameResolver->areNamesEqual($node, $propertyProperty)) { + if (! $this->nodeNameResolver->areNamesEqual($node, $propertyProperty)) { return false; } return in_array($node->getAttribute(AttributeKey::CLASS_NODE), $nodesToSearch, true); diff --git a/src/PhpParser/Node/NodeNameResolver/ClassConstFetchNameResolver.php b/src/PhpParser/Node/NodeNameResolver/ClassConstFetchNameResolver.php new file mode 100644 index 000000000000..db4cea02a165 --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/ClassConstFetchNameResolver.php @@ -0,0 +1,46 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function getNode(): string + { + return ClassConstFetch::class; + } + + /** + * @param ClassConstFetch $node + */ + public function resolve(Node $node): ?string + { + $class = $this->nodeNameResolver->getName($node->class); + $name = $this->nodeNameResolver->getName($node->name); + + if ($class === null || $name === null) { + return null; + } + + return $class . '::' . $name; + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/ClassConstNameResolver.php b/src/PhpParser/Node/NodeNameResolver/ClassConstNameResolver.php new file mode 100644 index 000000000000..aac470ca8791 --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/ClassConstNameResolver.php @@ -0,0 +1,45 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function getNode(): string + { + return ClassConst::class; + } + + /** + * @param ClassConst $node + */ + public function resolve(Node $node): ?string + { + if (count($node->consts) === 0) { + return null; + } + + $onlyConstant = $node->consts[0]; + + return $this->nodeNameResolver->getName($onlyConstant); + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/ClassNameResolver.php b/src/PhpParser/Node/NodeNameResolver/ClassNameResolver.php new file mode 100644 index 000000000000..52e520792795 --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/ClassNameResolver.php @@ -0,0 +1,47 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function getNode(): string + { + return Class_::class; + } + + /** + * @param Class_ $node + */ + public function resolve(Node $node): ?string + { + if (isset($node->namespacedName)) { + return $node->namespacedName->toString(); + } + + if ($node->name === null) { + return null; + } + + return $this->nodeNameResolver->getName($node->name); + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/EmptyNameResolver.php b/src/PhpParser/Node/NodeNameResolver/EmptyNameResolver.php new file mode 100644 index 000000000000..b559e5852ae5 --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/EmptyNameResolver.php @@ -0,0 +1,25 @@ +name instanceof Expr) { + return null; + } + + $functionName = $node->name; + + if (! $functionName instanceof Name) { + return (string) $functionName; + } + + $namespaceName = $functionName->getAttribute('namespacedName'); + if ($namespaceName instanceof FullyQualified) { + $functionFqnName = $namespaceName->toString(); + if (function_exists($functionFqnName)) { + return $functionFqnName; + } + } + + return (string) $functionName; + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/NameNameResolver.php b/src/PhpParser/Node/NodeNameResolver/NameNameResolver.php new file mode 100644 index 000000000000..c492a135af6d --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/NameNameResolver.php @@ -0,0 +1,32 @@ +getAttribute(AttributeKey::RESOLVED_NAME); + if ($resolvedName instanceof FullyQualified) { + return $resolvedName->toString(); + } + + return $node->toString(); + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/ParamNameResolver.php b/src/PhpParser/Node/NodeNameResolver/ParamNameResolver.php new file mode 100644 index 000000000000..0f6db0f7fe31 --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/ParamNameResolver.php @@ -0,0 +1,39 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function getNode(): string + { + return Param::class; + } + + /** + * @param Param $node + */ + public function resolve(Node $node): ?string + { + return $this->nodeNameResolver->getName($node->var); + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/PropertyNameResolver.php b/src/PhpParser/Node/NodeNameResolver/PropertyNameResolver.php new file mode 100644 index 000000000000..21fc410b8a6b --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/PropertyNameResolver.php @@ -0,0 +1,45 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function getNode(): string + { + return Property::class; + } + + /** + * @param Property $node + */ + public function resolve(Node $node): ?string + { + if (count($node->props) === 0) { + return null; + } + + $onlyProperty = $node->props[0]; + + return $this->nodeNameResolver->getName($onlyProperty); + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/UseNameResolver.php b/src/PhpParser/Node/NodeNameResolver/UseNameResolver.php new file mode 100644 index 000000000000..4218a5707e3e --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/UseNameResolver.php @@ -0,0 +1,45 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function getNode(): string + { + return Use_::class; + } + + /** + * @param Use_ $node + */ + public function resolve(Node $node): ?string + { + if (count($node->uses) === 0) { + return null; + } + + $onlyUse = $node->uses[0]; + + return $this->nodeNameResolver->getName($onlyUse); + } +} diff --git a/src/PhpParser/Node/NodeNameResolver/VariableNameResolver.php b/src/PhpParser/Node/NodeNameResolver/VariableNameResolver.php new file mode 100644 index 000000000000..3f2ab3ddaf61 --- /dev/null +++ b/src/PhpParser/Node/NodeNameResolver/VariableNameResolver.php @@ -0,0 +1,50 @@ +getAttribute(AttributeKey::PARENT_NODE); + // is $variable::method(), unable to resolve $variable->class name + if ($parentNode instanceof StaticCall) { + return null; + } + + // skip $some->$dynamicMethodName() + if ($parentNode instanceof MethodCall && $node === $parentNode->name) { + return null; + } + + // skip $some->$dynamicPropertyName + if ($parentNode instanceof PropertyFetch && $node === $parentNode->name) { + return null; + } + + if ($node->name instanceof Expr) { + return null; + } + + return (string) $node->name; + } +} diff --git a/src/PhpParser/Node/NodeVisitor/NodeRemovingNodeVisitor.php b/src/PhpParser/Node/NodeVisitor/NodeRemovingNodeVisitor.php index 629b06747187..08256538bffb 100644 --- a/src/PhpParser/Node/NodeVisitor/NodeRemovingNodeVisitor.php +++ b/src/PhpParser/Node/NodeVisitor/NodeRemovingNodeVisitor.php @@ -11,7 +11,7 @@ use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; use Rector\Core\PhpParser\Node\NodeFactory; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; final class NodeRemovingNodeVisitor extends NodeVisitorAbstract { @@ -26,18 +26,18 @@ final class NodeRemovingNodeVisitor extends NodeVisitorAbstract private $nodeFactory; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @param Stmt[] $nodesToRemove */ - public function __construct(array $nodesToRemove, NodeFactory $nodeFactory, NameResolver $nameResolver) + public function __construct(array $nodesToRemove, NodeFactory $nodeFactory, NodeNameResolver $nodeNameResolver) { $this->nodesToRemove = $nodesToRemove; $this->nodeFactory = $nodeFactory; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -59,7 +59,7 @@ public function enterNode(Node $node) continue; } - $methodName = $this->nameResolver->getName($node->name); + $methodName = $this->nodeNameResolver->getName($node->name); if ($methodName === null) { continue; } diff --git a/src/PhpParser/Node/NodeVisitorFactory/NodeRemovingNodeVisitorFactory.php b/src/PhpParser/Node/NodeVisitorFactory/NodeRemovingNodeVisitorFactory.php index e2be1205927b..d87d5e71022c 100644 --- a/src/PhpParser/Node/NodeVisitorFactory/NodeRemovingNodeVisitorFactory.php +++ b/src/PhpParser/Node/NodeVisitorFactory/NodeRemovingNodeVisitorFactory.php @@ -7,7 +7,7 @@ use PhpParser\Node; use Rector\Core\PhpParser\Node\NodeFactory; use Rector\Core\PhpParser\Node\NodeVisitor\NodeRemovingNodeVisitor; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; final class NodeRemovingNodeVisitorFactory { @@ -17,14 +17,14 @@ final class NodeRemovingNodeVisitorFactory private $nodeFactory; /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; - public function __construct(NodeFactory $nodeFactory, NameResolver $nameResolver) + public function __construct(NodeFactory $nodeFactory, NodeNameResolver $nodeNameResolver) { $this->nodeFactory = $nodeFactory; - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; } /** @@ -32,6 +32,6 @@ public function __construct(NodeFactory $nodeFactory, NameResolver $nameResolver */ public function createFromNodesToRemove(array $nodesToRemove): NodeRemovingNodeVisitor { - return new NodeRemovingNodeVisitor($nodesToRemove, $this->nodeFactory, $this->nameResolver); + return new NodeRemovingNodeVisitor($nodesToRemove, $this->nodeFactory, $this->nodeNameResolver); } } diff --git a/src/PhpParser/Node/Resolver/NameResolver.php b/src/PhpParser/Node/Resolver/NameResolver.php deleted file mode 100644 index 688bc14450b7..000000000000 --- a/src/PhpParser/Node/Resolver/NameResolver.php +++ /dev/null @@ -1,241 +0,0 @@ -isName($node, $name)) { - return true; - } - } - - return false; - } - - public function isName(Node $node, string $name): bool - { - if ($node instanceof MethodCall) { - // method call cannot have a name, only the variable or method name - return false; - } - - $resolvedName = $this->getName($node); - if ($resolvedName === null) { - return false; - } - - if ($name === '') { - return false; - } - - // is probably regex pattern - if ($this->isRegexPattern($name)) { - return (bool) Strings::match($resolvedName, $name); - } - - // is probably fnmatch - if (Strings::contains($name, '*')) { - return fnmatch($name, $resolvedName, FNM_NOESCAPE); - } - - // special case - if ($name === 'Object') { - return $name === $resolvedName; - } - - return strtolower($resolvedName) === strtolower($name); - } - - public function getName(Node $node): ?string - { - if ($node instanceof Empty_) { - return 'empty'; - } - - // more complex - if ($node instanceof ClassConst) { - if (count($node->consts) === 0) { - return null; - } - - return $this->getName($node->consts[0]); - } - - if ($node instanceof Property) { - if (count($node->props) === 0) { - return null; - } - - return $this->getName($node->props[0]); - } - - if ($node instanceof Use_) { - if (count($node->uses) === 0) { - return null; - } - - return $this->getName($node->uses[0]); - } - - if ($node instanceof Param) { - return $this->getName($node->var); - } - - if ($node instanceof Name) { - $resolvedName = $node->getAttribute(AttributeKey::RESOLVED_NAME); - if ($resolvedName instanceof FullyQualified) { - return $resolvedName->toString(); - } - - return $node->toString(); - } - - if ($node instanceof Class_) { - if (isset($node->namespacedName)) { - return $node->namespacedName->toString(); - } - if ($node->name === null) { - return null; - } - - return $this->getName($node->name); - } - - if ($node instanceof Interface_ || $node instanceof Trait_) { - return $this->resolveNamespacedNameAwareNode($node); - } - - if ($node instanceof ClassConstFetch) { - $class = $this->getName($node->class); - $name = $this->getName($node->name); - - if ($class === null || $name === null) { - return null; - } - - return $class . '::' . $name; - } - - if (! property_exists($node, 'name')) { - return null; - } - - // unable to resolve - if ($node->name instanceof Expr) { - return null; - } - - if ($node instanceof Variable) { - $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE); - // is $variable::method(), unable to resolve $variable->class name - if ($parentNode instanceof StaticCall) { - return null; - } - - // skip $some->$dynamicMethodName() - if ($parentNode instanceof MethodCall && $node === $parentNode->name) { - return null; - } - - // skip $some->$dynamicPropertyName - if ($parentNode instanceof PropertyFetch && $node === $parentNode->name) { - return null; - } - } - - if ($node instanceof FuncCall) { - return $this->resolveFuncCallName($node); - } - - return (string) $node->name; - } - - public function areNamesEqual(Node $firstNode, Node $secondNode): bool - { - return $this->getName($firstNode) === $this->getName($secondNode); - } - - private function isRegexPattern(string $name): bool - { - if (Strings::length($name) <= 2) { - return false; - } - - $firstChar = $name[0]; - $lastChar = $name[strlen($name) - 1]; - if ($firstChar !== $lastChar) { - return false; - } - - // this prevents miss matching like "aMethoda" - $possibleDelimiters = ['#', '~', '/']; - - return in_array($firstChar, $possibleDelimiters, true); - } - - /** - * @param Interface_|Trait_ $classLike - */ - private function resolveNamespacedNameAwareNode(ClassLike $classLike): ?string - { - if (isset($classLike->namespacedName)) { - return $classLike->namespacedName->toString(); - } - - if ($classLike->name === null) { - return null; - } - - return $this->getName($classLike->name); - } - - /** - * If some function is namespaced, it will be used over global one. - * But only if it really exists. - */ - private function resolveFuncCallName(Node $node): string - { - $functionName = $node->name; - if ($functionName instanceof Name) { - $namespaceName = $functionName->getAttribute('namespacedName'); - if ($namespaceName instanceof FullyQualified) { - $functionFqnName = $namespaceName->toString(); - if (function_exists($functionFqnName)) { - return $functionFqnName; - } - } - } - - return (string) $functionName; - } -} diff --git a/src/PhpParser/Node/Resolver/NodeNameResolver.php b/src/PhpParser/Node/Resolver/NodeNameResolver.php new file mode 100644 index 000000000000..39003ddc967c --- /dev/null +++ b/src/PhpParser/Node/Resolver/NodeNameResolver.php @@ -0,0 +1,150 @@ +nodeNameResolvers = $nodeNameResolvers; + } + + /** + * @param string[] $names + */ + public function isNames(Node $node, array $names): bool + { + foreach ($names as $name) { + if ($this->isName($node, $name)) { + return true; + } + } + + return false; + } + + public function isName(Node $node, string $name): bool + { + if ($node instanceof MethodCall) { + // method call cannot have a name, only the variable or method name + return false; + } + + $resolvedName = $this->getName($node); + if ($resolvedName === null) { + return false; + } + + if ($name === '') { + return false; + } + + // is probably regex pattern + if ($this->isRegexPattern($name)) { + return (bool) Strings::match($resolvedName, $name); + } + + // is probably fnmatch + if (Strings::contains($name, '*')) { + return fnmatch($name, $resolvedName, FNM_NOESCAPE); + } + + // special case + if ($name === 'Object') { + return $name === $resolvedName; + } + + return strtolower($resolvedName) === strtolower($name); + } + + public function getName(Node $node): ?string + { + foreach ($this->nodeNameResolvers as $nodeNameResolver) { + if (! is_a($node, $nodeNameResolver->getNode(), true)) { + continue; + } + + return $nodeNameResolver->resolve($node); + } + + // more complex + if ($node instanceof Interface_ || $node instanceof Trait_) { + return $this->resolveNamespacedNameAwareNode($node); + } + + if (! property_exists($node, 'name')) { + return null; + } + + // unable to resolve + if ($node->name instanceof Expr) { + return null; + } + + return (string) $node->name; + } + + public function areNamesEqual(Node $firstNode, Node $secondNode): bool + { + return $this->getName($firstNode) === $this->getName($secondNode); + } + + private function isRegexPattern(string $name): bool + { + if (Strings::length($name) <= 2) { + return false; + } + + $firstChar = $name[0]; + $lastChar = $name[strlen($name) - 1]; + if ($firstChar !== $lastChar) { + return false; + } + + // this prevents miss matching like "aMethoda" + $possibleDelimiters = ['#', '~', '/']; + + return in_array($firstChar, $possibleDelimiters, true); + } + + /** + * @param Interface_|Trait_ $classLike + */ + private function resolveNamespacedNameAwareNode(ClassLike $classLike): ?string + { + if (isset($classLike->namespacedName)) { + return $classLike->namespacedName->toString(); + } + + if ($classLike->name === null) { + return null; + } + + return $this->getName($classLike->name); + } +} diff --git a/src/PhpParser/Node/Value/ValueResolver.php b/src/PhpParser/Node/Value/ValueResolver.php index 78c25f66669a..3ad8fd2d6e2d 100644 --- a/src/PhpParser/Node/Value/ValueResolver.php +++ b/src/PhpParser/Node/Value/ValueResolver.php @@ -15,7 +15,7 @@ use PHPStan\Type\ConstantScalarType; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use Symplify\SmartFileSystem\SmartFileInfo; @@ -26,9 +26,9 @@ final class ValueResolver { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ConstExprEvaluator @@ -46,11 +46,11 @@ final class ValueResolver private $nodeTypeResolver; public function __construct( - NameResolver $nameResolver, + NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, ParsedNodeCollector $parsedNodeCollector ) { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->parsedNodeCollector = $parsedNodeCollector; $this->nodeTypeResolver = $nodeTypeResolver; } @@ -76,7 +76,7 @@ public function getValue(Expr $expr) } if ($expr instanceof ConstFetch) { - return $this->nameResolver->getName($expr); + return $this->nodeNameResolver->getName($expr); } $nodeStaticType = $this->nodeTypeResolver->getStaticType($expr); @@ -173,8 +173,8 @@ private function resolveFileConstant(File $file): string private function resolveClassConstFetch(ClassConstFetch $classConstFetch) { - $class = $this->nameResolver->getName($classConstFetch->class); - $constant = $this->nameResolver->getName($classConstFetch->name); + $class = $this->nodeNameResolver->getName($classConstFetch->class); + $constant = $this->nodeNameResolver->getName($classConstFetch->name); if ($class === null) { throw new ShouldNotHappenException(); diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index b35cda96c5cb..3efb299ea4ee 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -280,7 +280,7 @@ protected function isAnonymousClass(Node $node): bool return false; } - $className = $this->nameResolver->getName($node); + $className = $this->nodeNameResolver->getName($node); return $className === null || Strings::contains($className, 'AnonymousClass'); } diff --git a/src/Rector/AbstractRector/ComplexRemovalTrait.php b/src/Rector/AbstractRector/ComplexRemovalTrait.php index 602733745a66..0303f9892972 100644 --- a/src/Rector/AbstractRector/ComplexRemovalTrait.php +++ b/src/Rector/AbstractRector/ComplexRemovalTrait.php @@ -7,34 +7,11 @@ use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\BinaryOp; -use PhpParser\Node\Expr\BinaryOp\BooleanAnd; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; -use PhpParser\Node\Expr\BinaryOp\Coalesce; -use PhpParser\Node\Expr\BinaryOp\LogicalAnd; -use PhpParser\Node\Expr\BinaryOp\LogicalOr; -use PhpParser\Node\Expr\BitwiseNot; -use PhpParser\Node\Expr\BooleanNot; -use PhpParser\Node\Expr\Cast; -use PhpParser\Node\Expr\ClassConstFetch; -use PhpParser\Node\Expr\Clone_; -use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\ConstFetch; -use PhpParser\Node\Expr\Empty_; -use PhpParser\Node\Expr\Instanceof_; -use PhpParser\Node\Expr\Isset_; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\StaticPropertyFetch; -use PhpParser\Node\Expr\UnaryMinus; -use PhpParser\Node\Expr\UnaryPlus; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name; -use PhpParser\Node\Scalar; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Property; @@ -44,10 +21,13 @@ use Rector\Core\NodeContainer\NodeFinder\FunctionLikeParsedNodesFinder; use Rector\Core\PhpParser\Node\Commander\NodeRemovingCommander; use Rector\Core\PhpParser\Node\Manipulator\PropertyManipulator; +use Rector\DeadCode\NodeManipulator\LivingCodeManipulator; use Rector\NodeTypeResolver\Node\AttributeKey; /** + * Located in another trait ↓ * @property NodeRemovingCommander $nodeRemovingCommander + * @property FunctionLikeParsedNodesFinder $functionLikeParsedNodesFinder */ trait ComplexRemovalTrait { @@ -56,6 +36,11 @@ trait ComplexRemovalTrait */ protected $parsedNodeCollector; + /** + * @var LivingCodeManipulator + */ + protected $livingCodeManipulator; + /** * @var PropertyManipulator */ @@ -67,11 +52,11 @@ trait ComplexRemovalTrait public function autowireComplextRemovalTrait( PropertyManipulator $propertyManipulator, ParsedNodeCollector $parsedNodeCollector, - FunctionLikeParsedNodesFinder $functionLikeParsedNodesFinder + LivingCodeManipulator $livingCodeManipulator ): void { $this->parsedNodeCollector = $parsedNodeCollector; $this->propertyManipulator = $propertyManipulator; - $this->functionLikeParsedNodesFinder = $functionLikeParsedNodesFinder; + $this->livingCodeManipulator = $livingCodeManipulator; } abstract protected function removeNode(Node $node): void; @@ -106,15 +91,7 @@ protected function removePropertyAndUsages( continue; } - $assign = $propertyFetch->getAttribute(AttributeKey::PARENT_NODE); - - while ($assign !== null && ! $assign instanceof Assign) { - $assign = $assign->getAttribute(AttributeKey::PARENT_NODE); - } - - if (! $assign instanceof Assign) { - throw new ShouldNotHappenException("Can't handle this situation"); - } + $assign = $this->resolveAssign($propertyFetch); $this->removeAssignNode($assign); } @@ -129,7 +106,7 @@ protected function removePropertyAndUsages( foreach ($property->props as $prop) { if (! $this->nodeRemovingCommander->isNodeRemoved($prop)) { - //if the property has at least one node left -> return + // if the property has at least one node left -> return return; } } @@ -137,78 +114,6 @@ protected function removePropertyAndUsages( $this->removeNode($property); } - /** - * @param Node|int|string|null $expr - * @return Expr[] - */ - protected function keepLivingCodeFromExpr($expr): array - { - if (! $expr instanceof Node || - $expr instanceof Closure || - $expr instanceof Name || - $expr instanceof Identifier || - $expr instanceof Scalar || - $expr instanceof ConstFetch) { - return []; - } - if ($expr instanceof Cast || - $expr instanceof Empty_ || - $expr instanceof UnaryMinus || - $expr instanceof UnaryPlus || - $expr instanceof BitwiseNot || - $expr instanceof BooleanNot || - $expr instanceof Clone_) { - return $this->keepLivingCodeFromExpr($expr->expr); - } - if ($expr instanceof Variable) { - return $this->keepLivingCodeFromExpr($expr->name); - } - if ($expr instanceof PropertyFetch) { - return array_merge( - $this->keepLivingCodeFromExpr($expr->var), - $this->keepLivingCodeFromExpr($expr->name) - ); - } - if ($expr instanceof ArrayDimFetch) { - return array_merge( - $this->keepLivingCodeFromExpr($expr->var), - $this->keepLivingCodeFromExpr($expr->dim) - ); - } - if ($expr instanceof ClassConstFetch || - $expr instanceof StaticPropertyFetch) { - return array_merge( - $this->keepLivingCodeFromExpr($expr->class), - $this->keepLivingCodeFromExpr($expr->name) - ); - } - if ($expr instanceof BinaryOp - && ! ( - $expr instanceof LogicalAnd || - $expr instanceof BooleanAnd || - $expr instanceof LogicalOr || - $expr instanceof BooleanOr || - $expr instanceof Coalesce - )) { - return array_merge( - $this->keepLivingCodeFromExpr($expr->left), - $this->keepLivingCodeFromExpr($expr->right) - ); - } - if ($expr instanceof Instanceof_) { - return array_merge( - $this->keepLivingCodeFromExpr($expr->expr), - $this->keepLivingCodeFromExpr($expr->class) - ); - } - - if ($expr instanceof Isset_) { - return array_merge(...array_map([$this, 'keepLivingCodeFromExpr'], $expr->vars)); - } - - return [$expr]; - } - private function removeAssignNode(Assign $assign): void { $currentStatement = $assign->getAttribute(AttributeKey::CURRENT_STATEMENT); @@ -226,7 +131,7 @@ private function removeAssignNode(Assign $assign): void private function addLivingCodeBeforeNode(Expr $expr, Node $addBeforeThisNode): void { - foreach ($this->keepLivingCodeFromExpr($expr) as $expr) { + foreach ($this->livingCodeManipulator->keepLivingCodeFromExpr($expr) as $expr) { $this->addNodeBeforeNode(new Expression($expr), $addBeforeThisNode); } } @@ -262,4 +167,22 @@ private function shouldSkipPropertyForClassMethod(Expr $expr, array $classMethod return in_array($classMethodName, $classMethodNamesToSkip, true); } + + /** + * @param PropertyFetch|StaticPropertyFetch $expr + */ + private function resolveAssign(Expr $expr): Assign + { + $assign = $expr->getAttribute(AttributeKey::PARENT_NODE); + + while ($assign !== null && ! $assign instanceof Assign) { + $assign = $assign->getAttribute(AttributeKey::PARENT_NODE); + } + + if (! $assign instanceof Assign) { + throw new ShouldNotHappenException("Can't handle this situation"); + } + + return $assign; + } } diff --git a/src/Rector/AbstractRector/NameResolverTrait.php b/src/Rector/AbstractRector/NameResolverTrait.php index 98533173be1a..8400079c0dc7 100644 --- a/src/Rector/AbstractRector/NameResolverTrait.php +++ b/src/Rector/AbstractRector/NameResolverTrait.php @@ -8,7 +8,7 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name; use Rector\CodingStyle\Naming\ClassNaming; -use Rector\Core\PhpParser\Node\Resolver\NameResolver; +use Rector\Core\PhpParser\Node\Resolver\NodeNameResolver; /** * This could be part of @see AbstractRector, but decopuling to trait @@ -17,9 +17,9 @@ trait NameResolverTrait { /** - * @var NameResolver + * @var NodeNameResolver */ - private $nameResolver; + private $nodeNameResolver; /** * @var ClassNaming @@ -29,20 +29,20 @@ trait NameResolverTrait /** * @required */ - public function autowireNameResolverTrait(NameResolver $nameResolver, ClassNaming $classNaming): void + public function autowireNameResolverTrait(NodeNameResolver $nodeNameResolver, ClassNaming $classNaming): void { - $this->nameResolver = $nameResolver; + $this->nodeNameResolver = $nodeNameResolver; $this->classNaming = $classNaming; } public function isName(Node $node, string $name): bool { - return $this->nameResolver->isName($node, $name); + return $this->nodeNameResolver->isName($node, $name); } public function areNamesEqual(Node $firstNode, Node $secondNode): bool { - return $this->nameResolver->areNamesEqual($firstNode, $secondNode); + return $this->nodeNameResolver->areNamesEqual($firstNode, $secondNode); } /** @@ -50,12 +50,12 @@ public function areNamesEqual(Node $firstNode, Node $secondNode): bool */ public function isNames(Node $node, array $names): bool { - return $this->nameResolver->isNames($node, $names); + return $this->nodeNameResolver->isNames($node, $names); } public function getName(Node $node): ?string { - return $this->nameResolver->getName($node); + return $this->nodeNameResolver->getName($node); } /** diff --git a/src/Rector/MethodBody/NormalToFluentRector.php b/src/Rector/MethodBody/NormalToFluentRector.php index c10b4ed3903a..3a74af5b6ccf 100644 --- a/src/Rector/MethodBody/NormalToFluentRector.php +++ b/src/Rector/MethodBody/NormalToFluentRector.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use Rector\Core\Rector\AbstractRector; @@ -81,21 +82,12 @@ public function refactor(Node $node): ?Node // iterate from bottom to up, so we can merge for ($i = $classMethodStatementCount - 1; $i >= 0; --$i) { $stmt = $node->stmts[$i]; - - // we look only for 2+ stmts - if (! isset($node->stmts[$i - 1])) { - continue; - } - - // we look for 2 methods calls in a row - if (! $stmt instanceof Expression) { + if ($this->shouldSkipPreviousStmt($node, $i, $stmt)) { continue; } + /** @var Expression $prevStmt */ $prevStmt = $node->stmts[$i - 1]; - if (! $prevStmt instanceof Expression) { - continue; - } // here are 2 method calls statements in a row, while current one is first one if (! $this->isBothMethodCallMatch($stmt, $prevStmt)) { @@ -105,7 +97,6 @@ public function refactor(Node $node): ?Node // reset for new type $this->collectedMethodCalls = []; - continue; } @@ -193,4 +184,21 @@ private function matchMethodCall(MethodCall $methodCall): ?string return null; } + + private function shouldSkipPreviousStmt(Node $node, int $i, Stmt $stmt): bool + { + // we look only for 2+ stmts + if (! isset($node->stmts[$i - 1])) { + return true; + } + + // we look for 2 methods calls in a row + if (! $stmt instanceof Expression) { + return true; + } + + $prevStmt = $node->stmts[$i - 1]; + + return ! $prevStmt instanceof Expression; + } } diff --git a/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php b/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php index 50bada08e808..bf6d57066513 100644 --- a/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php +++ b/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php @@ -128,22 +128,8 @@ private function processNamespaceNodes( /** @var ClassLike[] $classLikes */ $classLikes = $this->betterNodeFinder->findClassLikes($nodes); - if (count($classLikes) <= 1) { - continue; - } - foreach ($classLikes as $classLikeNode) { - $this->removeAllClassLikesFromNamespaceNode($newStmt); - $newStmt->stmts[] = $classLikeNode; - - $fileDestination = $this->createClassLikeFileDestination($classLikeNode, $smartFileInfo); - - // has file changed? - if ($shouldDeleteFile) { - $this->printNewNodesToFilePath($newStmtsSet, $fileDestination); - } else { - $this->printNodesToFilePath($newStmtsSet, $fileDestination); - } + $this->refactorClassLike($smartFileInfo, $shouldDeleteFile, $newStmt, $classLikeNode, $newStmtsSet); } } } @@ -214,4 +200,24 @@ private function createClassLikeFileDestination(ClassLike $classLike, SmartFileI return $currentDirectory . DIRECTORY_SEPARATOR . $classLike->name . '.php'; } + + private function refactorClassLike( + SmartFileInfo $smartFileInfo, + bool $shouldDeleteFile, + Namespace_ $newStmt, + ClassLike $classLike, + array $newStmtsSet + ): void { + $this->removeAllClassLikesFromNamespaceNode($newStmt); + $newStmt->stmts[] = $classLike; + + $fileDestination = $this->createClassLikeFileDestination($classLike, $smartFileInfo); + + // has file changed? + if ($shouldDeleteFile) { + $this->printNewNodesToFilePath($newStmtsSet, $fileDestination); + } else { + $this->printNodesToFilePath($newStmtsSet, $fileDestination); + } + } }