From a4b40c60c4d288f3c9b49474ddf7a9bc0e699063 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 9 Mar 2019 13:23:11 +0000 Subject: [PATCH] remove complicated examples, updated README with real use-cases --- README.md | 8 +- composer.json | 1 - ecs.yml | 1 - examples/ConfiguredProvideConfigRector.php | 132 --------- examples/MergeIsCandidateRector.php | 310 --------------------- 5 files changed, 4 insertions(+), 448 deletions(-) delete mode 100644 examples/ConfiguredProvideConfigRector.php delete mode 100644 examples/MergeIsCandidateRector.php diff --git a/README.md b/README.md index ede269c24aa..bbd169fd784 100644 --- a/README.md +++ b/README.md @@ -36,12 +36,12 @@ Rector **instantly upgrades and instantly refactors PHP code of your application **Rector can**: -- Rename classes, methods and properties -- Rename partial namespace -- Rename pseudo-namespace to namespace +- Rename classes, methods, properties, namespaces, constants... anything :) - Add, replace or remove arguments -- Add arguments or return typehint +- Add [parameter or return type declarations](https://www.tomasvotruba.cz/blog/2019/01/03/how-to-complete-type-declarations-without-docblocks-with-rector/) without docblocks - just with static analysis - Change visibility of constant, property or method +- Upgrade from PHP 5.3 to PHP 7.4 +- [Complete PHP 7.4 property type declarations](https://www.tomasvotruba.cz/blog/2018/11/15/how-to-get-php-74-typed-properties-to-your-code-in-few-seconds/) - And much more... ...**look at overview of [all available Rectors](/docs/AllRectorsOverview.md)** with before/after diffs and configuration examples. You can use them to build your own sets. diff --git a/composer.json b/composer.json index 828d4291a51..2ff4be35b29 100644 --- a/composer.json +++ b/composer.json @@ -89,7 +89,6 @@ "Rector\\PHPStanExtensions\\": "utils/PHPStanExtensions/src" }, "classmap": [ - "examples", "packages/Symfony/tests/Rector/FrameworkBundle/AbstractToConstructorInjectionRectorSource", "packages/Symfony/tests/Rector/FrameworkBundle/ContainerGetToConstructorInjectionRector/Source", "packages/NodeTypeResolver/tests/PerNodeTypeResolver/ParamTypeResolver/Source", diff --git a/ecs.yml b/ecs.yml index 9d2b5058457..94a603849ad 100644 --- a/ecs.yml +++ b/ecs.yml @@ -109,7 +109,6 @@ parameters: - 'packages/Php/src/EregToPcreTransformer.php' # dev - 'packages/Php/src/Rector/FunctionLike/*TypeDeclarationRector.php' - - 'examples/*' - 'packages/Php/src/Rector/If_/IfToSpaceshipRector.php' Symplify\CodingStandard\Sniffs\ControlStructure\SprintfOverContactSniff: diff --git a/examples/ConfiguredProvideConfigRector.php b/examples/ConfiguredProvideConfigRector.php deleted file mode 100644 index 16a0ad6e80f..00000000000 --- a/examples/ConfiguredProvideConfigRector.php +++ /dev/null @@ -1,132 +0,0 @@ -classManipulator = $classManipulator; - $this->builderFactory = $builderFactory; - } - - public function getDefinition(): RectorDefinition - { - return new RectorDefinition('Simplify tests', [new CodeSample('', '')]); - } - - /** - * @return string[] - */ - public function getNodeTypes(): array - { - return [Class_::class]; - } - - /** - * @param Class_ $node - */ - public function refactor(Node $node): ?Node - { - if (! $this->isType($node, AbstractRectorTestCase::class) || $node->isAbstract()) { - return null; - } - - $classMethodsByName = $this->classManipulator->getMethodsByName($node); - if (! isset($classMethodsByName['provideConfig'])) { - return null; - } - - // already changed - if (isset($classMethodsByName['getRectorConfiguration'])) { - return null; - } - - $provideConfigMethod = $classMethodsByName['provideConfig']; - - if ($provideConfigMethod->stmts[0] instanceof Return_) { - /** @var Return_ $returnNode */ - $returnNode = $provideConfigMethod->stmts[0]; - - $configPath = $this->getValue($returnNode->expr); - $yaml = Yaml::parseFile($configPath); - - $resolved = $this->resolveClassToConfigurationFromConfig($yaml); - if ($resolved === null) { - return null; - } - - [$class, $configuration] = $resolved; - - $returnNode = new Return_($this->createClassConstant($class, 'class')); - $node->stmts[] = $this->builderFactory->method('getRectorClass') - ->makeProtected() - ->setReturnType('string') - ->addStmt($returnNode) - ->getNode(); - - $returnNode = new Return_(BuilderHelpers::normalizeValue($configuration)); - $node->stmts[] = $this->builderFactory->method('getRectorConfiguration') - ->makeProtected() - ->setReturnType('array') - ->setDocComment("/**\n * @return mixed[]\n */") - ->addStmt($returnNode) - ->getNode(); - - $this->removeNode($provideConfigMethod); - - // remove config file - unlink($configPath); - } - - return $node; - } - - /** - * @param mixed[] $yaml - * @return mixed[]|null - */ - private function resolveClassToConfigurationFromConfig(array $yaml): ?array - { - if (count($yaml) !== 1) { - return null; - } - - if (!isset($yaml['services'])) { - return null; - } - - // has only "services" keys - if (count($yaml['services']) !== 1) { - return null; - } - - $class = key($yaml['services']); - // only service - $configuration = array_pop($yaml['services']); - - return [$class, $configuration]; - } -} diff --git a/examples/MergeIsCandidateRector.php b/examples/MergeIsCandidateRector.php deleted file mode 100644 index 94a56e9e312..00000000000 --- a/examples/MergeIsCandidateRector.php +++ /dev/null @@ -1,310 +0,0 @@ -builderFactory = $builderFactory; - $this->docBlockManipulator = $docBlockManipulator; - $this->callableNodeTraverser = $callableNodeTraverser; - } - - public function getDefinition(): RectorDefinition - { - return new RectorDefinition( - 'Finds all "Rector\Rector\AbstractRector" instances, merges "isCandidate()" method to "refactor()" method and creates "getNodeType()" method by @param annotation of "refactor()" method.', - [new CodeSample('', '')] - ); - } - - /** - * @return string[] - */ - public function getNodeTypes(): array - { - return [Class_::class]; - } - - /** - * @param Class_ $node - */ - public function refactor(Node $node): ?Node - { - if (! $this->isType($node, AbstractRector::class)) { - return null; - } - - if (! $node->isAbstract()) { - return null; - } - - // has "isCandidate()" method? - if (! $this->hasClassIsCandidateMethod($node)) { - return null; - } - - [$isCandidateClassMethodPosition, $isCandidateClassMethod] = $this->getClassMethodByName($node, 'isCandidate'); - [$refactorClassMethodPosition, $refactorClassMethod] = $this->getClassMethodByName($node, 'refactor'); - - if ($refactorClassMethod === null) { - return null; - } - - // 1. replace "isCandidate()" method by "getNodeType()" method - $node->stmts[$isCandidateClassMethodPosition] = $this->createGetNodeTypeClassMethod($refactorClassMethod); - - // 2. rename "return false;" to "return null;" to respect "refactor(Node $node): ?Node" typehint - $this->replaceReturnFalseWithReturnNull($isCandidateClassMethod); - - // 3. rename used variable "$node" to "$specificTypeParam" - $this->renameNodeToParamNode($isCandidateClassMethod, $refactorClassMethod->params[0]->var->name); - - // 4. turn last return in "isCondition()" with early return - $this->replaceLastReturnWithIf($isCandidateClassMethod); - - // 5. return true makes no sense anymore, just continue - $this->removeReturnTrue($isCandidateClassMethod); - - // 6. remove first "instanceof", already covered by getNodeType() - $isCandidateClassMethod = $this->removeFirstInstanceOf($isCandidateClassMethod); - - // 7. add contents of "isCandidate()" method to start of "refactor()" method - $refactorClassMethod->stmts = array_merge($isCandidateClassMethod->stmts, $refactorClassMethod->stmts); - - $node->stmts[$refactorClassMethodPosition] = $refactorClassMethod; - - return $node; - } - - private function hasClassIsCandidateMethod(Class_ $classNode): bool - { - return (bool) $this->getClassMethodByName($classNode, 'isCandidate'); - } - - /** - * @return int[]|ClassMethod[]|null - */ - private function getClassMethodByName(Class_ $classNode, string $name) - { - foreach ($classNode->stmts as $i => $stmt) { - if (! $stmt instanceof ClassMethod) { - continue; - } - - if ($this->isName($stmt->name, $name)) { - return [$i, $stmt]; - } - } - - return null; - } - - /** - * @return string[] - */ - private function resolveParamTagValueNodeToStrings(ParamTagValueNode $paramTagValueNode): array - { - $types = []; - - if ($paramTagValueNode->type instanceof UnionTypeNode) { - foreach ($paramTagValueNode->type->types as $type) { - $types[] = (string) $type; - } - } elseif ($paramTagValueNode->type instanceof IdentifierTypeNode) { - $types[] = $paramTagValueNode->type->name; - } - // todo: resolve - - return $types; - } - - private function createGetNodeTypeClassMethod(ClassMethod $refactorClassMethod): ClassMethod - { - $paramTypes = $this->resolveSingleParamTypesFromClassMethod($refactorClassMethod); - - $nodeToBeReturned = new Array_(); - - if (count($paramTypes) > 1) { - foreach ($paramTypes as $paramType) { - $classConstFetchNode = $this->createClassConstant($paramType, 'class'); - $nodeToBeReturned->items[] = new ArrayItem($classConstFetchNode); - } - } elseif (count($paramTypes) === 1) { - $nodeToBeReturned->items[] = $this->createClassConstant($paramTypes[0], 'class'); - } else { // fallback to basic node - $nodeToBeReturned->items[] = $this->createClassConstant(Node::class, 'class'); - } - - return $this->builderFactory->method('getNodeTypes') - ->makePublic() - ->setReturnType('array') - ->addStmt(new Return_($nodeToBeReturned)) - ->getNode(); - } - - /** - * @return string[] - */ - private function resolveSingleParamTypesFromClassMethod(ClassMethod $classMethod): array - { - // add getNodeType() by $refactorClassMethod "@param" doc type - if (! $this->docBlockManipulator->hasTag($classMethod, 'param')) { - return []; - } - - $paramNode = $this->docBlockManipulator->getTagByName($classMethod, 'param'); - - /** @var ParamTagValueNode $paramTagValueNode */ - $paramTagValueNode = $paramNode->value; - - return $this->resolveParamTagValueNodeToStrings($paramTagValueNode); - } - - private function replaceReturnFalseWithReturnNull(ClassMethod $classMethod): void - { - $this->callableNodeTraverser->traverseNodesWithCallable([$classMethod], function (Node $node): ?Node { - if (! $node instanceof Return_ || ! $node->expr instanceof ConstFetch) { - return null; - } - - if ($this->isFalse($node->expr)) { - return new Return_(new ConstFetch(new Name('null'))); - } - - return null; - }); - } - - private function renameNodeToParamNode(ClassMethod $classMethod, string $nodeName): void - { - $this->callableNodeTraverser->traverseNodesWithCallable([$classMethod], function (Node $node) use ( - $nodeName - ): ?Node { - if (! $node instanceof Variable || ! $this->isName($node, 'node')) { - return null; - } - - $node->name = $nodeName; - - return $node; - }); - } - - private function replaceLastReturnWithIf(ClassMethod $classMethod): void - { - $this->callableNodeTraverser->traverseNodesWithCallable([$classMethod], function (Node $node): ?Node { - if (! $node instanceof Return_) { - return null; - } - - if ($node->expr instanceof ConstFetch) { - return null; - } - - $identicalCondition = new Identical($node->expr, new ConstFetch(new Name('false'))); - return new If_($identicalCondition, [ - 'stmts' => [new Return_(new ConstFetch(new Name('null')))], - ]); - }); - } - - private function removeReturnTrue(ClassMethod $classMethod): void - { - $this->callableNodeTraverser->traverseNodesWithCallable([$classMethod], function (Node $node): ?Node { - if (! $node instanceof Return_ || ! $node->expr instanceof ConstFetch || ! $this->isTrue($node->expr)) { - return null; - } - - return new Nop(); - }); - } - - private function removeFirstInstanceOf(ClassMethod $classMethod): ClassMethod - { - if (! isset($classMethod->stmts[0])) { - return $classMethod; - } - - if (! $classMethod->stmts[0] instanceof If_) { - return $classMethod; - } - - /** @var If_ $ifNode */ - $ifNode = $classMethod->stmts[0]; - if (! $ifNode->stmts[0] instanceof Return_) { - return $classMethod; - } - - /** @var Return_ $returnNode */ - $returnNode = $ifNode->stmts[0]; - if (! $returnNode->expr instanceof ConstFetch) { - return $classMethod; - } - - $constFetchNode = $returnNode->expr; - if ($constFetchNode->name->toString() === null) { - unset($classMethod->stmts[0]); - } - - return $classMethod; - } -}