From 2beb152e5f43bbedb850bd98afbc2a98b9abefd8 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 6 Aug 2017 18:51:23 +0200 Subject: [PATCH 01/22] [UpgradeDeprecation] add ReplaceDeprecatedConstantNodeVisitor --- easy-coding-standard.neon | 1 + src/Application/FileProcessor.php | 6 +- .../ReplaceDeprecatedConstantNodeVisitor.php | 73 +++++++++++++++++++ ...rinter.php => FormatPerservingPrinter.php} | 2 +- src/Testing/Application/FileReconstructor.php | 6 +- .../Test.php | 16 ++++ .../correct/correct.php.inc | 9 +++ .../wrong/wrong.php.inc | 9 +++ 8 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php rename src/Printer/{CodeStyledPrinter.php => FormatPerservingPrinter.php} (95%) create mode 100644 tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/Test.php create mode 100644 tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/correct/correct.php.inc create mode 100644 tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/wrong/wrong.php.inc diff --git a/easy-coding-standard.neon b/easy-coding-standard.neon index eea2d6643c1..34fd198c531 100644 --- a/easy-coding-standard.neon +++ b/easy-coding-standard.neon @@ -1,5 +1,6 @@ includes: - vendor/symplify/easy-coding-standard/config/psr2-checkers.neon + - vendor/symplify/easy-coding-standard/config/php70-checkers.neon - vendor/symplify/easy-coding-standard/config/php71-checkers.neon checkers: diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index 45e31f70d56..cf614cc829d 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -5,7 +5,7 @@ namespace Rector\Application; use PhpParser\Lexer; use PhpParser\NodeTraverser; use PhpParser\Parser; -use Rector\Printer\CodeStyledPrinter; +use Rector\Printer\FormatPerservingPrinter; use SplFileInfo; final class FileProcessor @@ -16,7 +16,7 @@ final class FileProcessor private $parser; /** - * @var CodeStyledPrinter + * @var FormatPerservingPrinter */ private $codeStyledPrinter; @@ -30,7 +30,7 @@ final class FileProcessor */ private $lexer; - public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, Lexer $lexer, NodeTraverser $nodeTraverser) + public function __construct(Parser $parser, FormatPerservingPrinter $codeStyledPrinter, Lexer $lexer, NodeTraverser $nodeTraverser) { $this->parser = $parser; $this->codeStyledPrinter = $codeStyledPrinter; diff --git a/src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php new file mode 100644 index 00000000000..b745948c6aa --- /dev/null +++ b/src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php @@ -0,0 +1,73 @@ + $node stays as-is + * * NodeTraverser::DONT_TRAVERSE_CHILDREN + * => Children of $node are not traversed. $node stays as-is + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * otherwise + * => $node is set to the return value. + * + * @return null|int|Node + */ + public function enterNode(Node $node): ?int + { + if ($this->isCandidate($node)) { + $this->refactor($node); + return NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + + return null; + } + + private function isCandidate(Node $node): bool + { + if ($node instanceof ClassConstFetch) { + if ((string) $node->class !== $this->getClassName()) { + return false; + } + + if ((string) $node->name !== $this->getOldConstantName()) { + return false; + } + + return true; + } + + return false; + } + + private function refactor(ClassConstFetch $classConstFetchNode): void + { + $classConstFetchNode->name->name = $this->getNewConstantName(); + } +} diff --git a/src/Printer/CodeStyledPrinter.php b/src/Printer/FormatPerservingPrinter.php similarity index 95% rename from src/Printer/CodeStyledPrinter.php rename to src/Printer/FormatPerservingPrinter.php index 08ea5addb20..ca6a78676e3 100644 --- a/src/Printer/CodeStyledPrinter.php +++ b/src/Printer/FormatPerservingPrinter.php @@ -5,7 +5,7 @@ namespace Rector\Printer; use PhpParser\PrettyPrinter\Standard; use SplFileInfo; -final class CodeStyledPrinter +final class FormatPerservingPrinter { /** * @var Standard diff --git a/src/Testing/Application/FileReconstructor.php b/src/Testing/Application/FileReconstructor.php index 7bd390afd37..5ab8f87ed92 100644 --- a/src/Testing/Application/FileReconstructor.php +++ b/src/Testing/Application/FileReconstructor.php @@ -6,7 +6,7 @@ use PhpParser\Lexer; use PhpParser\NodeTraverser; use PhpParser\Parser; use Rector\NodeTraverser\StateHolder; -use Rector\Printer\CodeStyledPrinter; +use Rector\Printer\FormatPerservingPrinter; use SplFileInfo; final class FileReconstructor @@ -17,7 +17,7 @@ final class FileReconstructor private $parser; /** - * @var CodeStyledPrinter + * @var FormatPerservingPrinter */ private $codeStyledPrinter; @@ -38,7 +38,7 @@ final class FileReconstructor public function __construct( Parser $parser, - CodeStyledPrinter $codeStyledPrinter, + FormatPerservingPrinter $codeStyledPrinter, Lexer $lexer, NodeTraverser $nodeTraverser, StateHolder $stateHolder diff --git a/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/Test.php b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/Test.php new file mode 100644 index 00000000000..9704e2f688a --- /dev/null +++ b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/Test.php @@ -0,0 +1,16 @@ +doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong.php.inc', + __DIR__ . '/correct/correct.php.inc' + ); + } +} diff --git a/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/correct/correct.php.inc b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/correct/correct.php.inc new file mode 100644 index 00000000000..5cf52e94219 --- /dev/null +++ b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/correct/correct.php.inc @@ -0,0 +1,9 @@ + Date: Sun, 6 Aug 2017 19:00:25 +0200 Subject: [PATCH 02/22] fix composer shortcut --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c889cbfc46e..565724bf3ed 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ } }, "scripts": { - "all": ["phpunit", "@cs", "@ps"], + "all": ["phpunit", "@check-cs", "@phpstan"], "check-cs": "ecs check bin src tests", "fix-cs": "ecs check bin src tests --fix", "phpstan": "phpstan analyse bin src tests --level 7 --configuration phpstan.neon" From f8420008f372284bd4825e539c8c1530f34cf3a2 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 6 Aug 2017 19:26:39 +0200 Subject: [PATCH 03/22] [NodeVisitor] make ReplaceDeprecatedConstant abstract --- src/DependencyInjection/AppKernel.php | 12 +++++++++- src/DependencyInjection/ContainerFactory.php | 8 +++++++ ...eReplaceDeprecatedConstantNodeVisitor.php} | 19 ++++----------- .../PHPUnit/AbstractReconstructorTestCase.php | 3 +-- src/config/services.yml | 1 - .../ReplaceOldConstantNodeVisitor.php | 23 +++++++++++++++++++ .../Test.php | 2 +- tests/config/services.yml | 6 +++++ 8 files changed, 54 insertions(+), 20 deletions(-) rename src/NodeVisitor/UpgradeDeprecation/{ReplaceDeprecatedConstantNodeVisitor.php => AbstraceReplaceDeprecatedConstantNodeVisitor.php} (77%) create mode 100644 tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php create mode 100644 tests/config/services.yml diff --git a/src/DependencyInjection/AppKernel.php b/src/DependencyInjection/AppKernel.php index a5206e86e43..8b9414a2166 100644 --- a/src/DependencyInjection/AppKernel.php +++ b/src/DependencyInjection/AppKernel.php @@ -10,14 +10,24 @@ use Symfony\Component\HttpKernel\Kernel; final class AppKernel extends Kernel { - public function __construct() + /** + * @var string + */ + private $config; + + public function __construct(?string $config = '') { + $this->config = $config; parent::__construct('dev', true); } public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load(__DIR__ . '/../config/services.yml'); + + if ($this->config) { + $loader->load($this->config); + } } public function getCacheDir(): string diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index ab7893626f3..690fd12c594 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -13,4 +13,12 @@ final class ContainerFactory return $appKernel->getContainer(); } + + public function createWithConfig(string $config): ContainerInterface + { + $appKernel = new AppKernel($config); + $appKernel->boot(); + + return $appKernel->getContainer(); + } } diff --git a/src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php similarity index 77% rename from src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php rename to src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php index b745948c6aa..013a6ba0a1d 100644 --- a/src/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor.php +++ b/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php @@ -7,24 +7,13 @@ use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; -final class ReplaceDeprecatedConstantNodeVisitor extends NodeVisitorAbstract +abstract class AbstraceReplaceDeprecatedConstantNodeVisitor extends NodeVisitorAbstract { - // this will be in specific node visitor, now hardcoded + abstract public function getClassName(): string; - public function getClassName(): string - { - return'ClassWithConstants'; - } + abstract public function getOldConstantName(): string; - public function getOldConstantName(): string - { - return 'OLD_CONSTANT'; - } - - public function getNewConstantName(): string - { - return 'NEW_CONSTANT'; - } + abstract public function getNewConstantName(): string; /** * Return value semantics: diff --git a/src/Testing/PHPUnit/AbstractReconstructorTestCase.php b/src/Testing/PHPUnit/AbstractReconstructorTestCase.php index 5014fa3e7f6..f3dcce41136 100644 --- a/src/Testing/PHPUnit/AbstractReconstructorTestCase.php +++ b/src/Testing/PHPUnit/AbstractReconstructorTestCase.php @@ -2,7 +2,6 @@ namespace Rector\Testing\PHPUnit; -use PhpParser\NodeVisitor; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Rector\DependencyInjection\ContainerFactory; @@ -23,7 +22,7 @@ abstract class AbstractReconstructorTestCase extends TestCase protected function setUp(): void { - $this->container = (new ContainerFactory)->create(); + $this->container = (new ContainerFactory)->createWithConfig(__DIR__ . '/../../../tests/config/services.yml'); $this->fileReconstructor = $this->container->get(FileReconstructor::class); } diff --git a/src/config/services.yml b/src/config/services.yml index 526168dd2ed..3642becdbe5 100644 --- a/src/config/services.yml +++ b/src/config/services.yml @@ -5,7 +5,6 @@ parameters: services: _defaults: autowire: true - autoconfigure: true # PSR-4 autodiscovery Rector\: diff --git a/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php new file mode 100644 index 00000000000..0c44d5f8cf5 --- /dev/null +++ b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php @@ -0,0 +1,23 @@ + Date: Sun, 6 Aug 2017 19:30:19 +0200 Subject: [PATCH 04/22] fix travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6c513ae2509..179a4f35d82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,9 @@ script: - vendor/bin/phpunit $PHPUNIT_FLAGS # check coding standard (defined in composer.json "scripts" section) # if this fails, run "composer fs" to fix all fixable issues - - composer cs + - composer check-cs # check with phpstan (defined in composer.json "scripts" section) - - composer ps + # - composer phpstan after_script: # upload coverage.xml file to Coveralls to analyze it From 63bbfb3efc3b1dc5a13ddba7f4b37438bdbd9087 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 6 Aug 2017 19:37:55 +0200 Subject: [PATCH 05/22] improve coding standard, add DeprectionInterface --- easy-coding-standard.neon | 62 +++++++++++++++++++ src/Application/FileProcessor.php | 8 ++- src/Console/Command/ReconstructCommand.php | 10 +-- .../Deprecation/DeprecationInterface.php | 21 +++++++ src/Deprecation/SetNames.php | 16 +++++ .../GetterToPropertyNodeVisitor.php | 4 +- .../ReplaceOldConstantNodeVisitor.php | 2 +- 7 files changed, 113 insertions(+), 10 deletions(-) create mode 100644 src/Contract/Deprecation/DeprecationInterface.php create mode 100644 src/Deprecation/SetNames.php diff --git a/easy-coding-standard.neon b/easy-coding-standard.neon index 34fd198c531..c78cfa5ad25 100644 --- a/easy-coding-standard.neon +++ b/easy-coding-standard.neon @@ -4,3 +4,65 @@ includes: - vendor/symplify/easy-coding-standard/config/php71-checkers.neon checkers: + # Slevomat + - SlevomatCodingStandard\Sniffs\ControlStructures\DisallowEqualOperatorsSniff + - SlevomatCodingStandard\Sniffs\ControlStructures\YodaComparisonSniff + - SlevomatCodingStandard\Sniffs\Exceptions\DeadCatchSniff + - SlevomatCodingStandard\Sniffs\Exceptions\ReferenceThrowableOnlySniff + - SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff + - SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff + + # Files + PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff: + absoluteLineLimit: 120 + + # PSR-4 + - PhpCsFixer\Fixer\Basic\Psr4Fixer + + # Code Analysis + - PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\EmptyStatementSniff + PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff: + absoluteComplexity: 10 + PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff: + absoluteNestingLevel: 5 + + # Naming Conventions + - PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff + + # PHP + - PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\NonExecutableCodeSniff + + # WhiteSpace + - PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\LanguageConstructSpacingSniff + PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SuperfluousWhitespaceSniff: + ignoreBlankLines: false + + # Namespaces + - PhpCsFixer\Fixer\Import\OrderedImportsFixer + + PhpCsFixer\Fixer\Operator\ConcatSpaceFixer: + spacing: one + - PhpCsFixer\Fixer\ClassNotation\OrderedClassElementsFixer + - PhpCsFixer\Fixer\LanguageConstruct\DirConstantFixer + - PhpCsFixer\Fixer\CastNotation\ModernizeTypesCastingFixer + - PhpCsFixer\Fixer\Semicolon\SemicolonAfterInstructionFixer + - PhpCsFixer\Fixer\Operator\NotOperatorWithSuccessorSpaceFixer + - PhpCsFixer\Fixer\ControlStructure\NoUselessElseFixer + - PhpCsFixer\Fixer\ReturnNotation\NoUselessReturnFixer + - PhpCsFixer\Fixer\LanguageConstruct\CombineConsecutiveUnsetsFixer + - PhpCsFixer\Fixer\Strict\StrictComparisonFixer + PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer: + annotations: + - author + - throws + - expectedException + + # PHPUnit + - PhpCsFixer\Fixer\PhpUnit\PhpUnitStrictFixer + + # new since PhpCsFixer 2.2-2.4 + - PhpCsFixer\Fixer\Phpdoc\PhpdocReturnSelfReferenceFixer + - PhpCsFixer\Fixer\LanguageConstruct\IsNullFixer + - PhpCsFixer\Fixer\Basic\NonPrintableCharacterFixer + - PhpCsFixer\Fixer\Phpdoc\PhpdocTypesOrderFixer + - PhpCsFixer\Fixer\Comment\SingleLineCommentStyleFixer \ No newline at end of file diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index cf614cc829d..bffc03fda1a 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -30,8 +30,12 @@ final class FileProcessor */ private $lexer; - public function __construct(Parser $parser, FormatPerservingPrinter $codeStyledPrinter, Lexer $lexer, NodeTraverser $nodeTraverser) - { + public function __construct( + Parser $parser, + FormatPerservingPrinter $codeStyledPrinter, + Lexer $lexer, + NodeTraverser $nodeTraverser + ) { $this->parser = $parser; $this->codeStyledPrinter = $codeStyledPrinter; $this->nodeTraverser = $nodeTraverser; diff --git a/src/Console/Command/ReconstructCommand.php b/src/Console/Command/ReconstructCommand.php index 832a7a4b66b..76991593bd5 100644 --- a/src/Console/Command/ReconstructCommand.php +++ b/src/Console/Command/ReconstructCommand.php @@ -17,6 +17,11 @@ final class ReconstructCommand extends Command */ private const NAME = 'reconstruct'; + /** + * @var string + */ + private const ARGUMENT_SOURCE_NAME = 'source'; + /** * @var FileProcessor */ @@ -29,11 +34,6 @@ final class ReconstructCommand extends Command parent::__construct(); } - /** - * @var string - */ - private const ARGUMENT_SOURCE_NAME = 'source'; - protected function configure(): void { $this->setName(self::NAME); diff --git a/src/Contract/Deprecation/DeprecationInterface.php b/src/Contract/Deprecation/DeprecationInterface.php new file mode 100644 index 00000000000..a2bbc3eaeb9 --- /dev/null +++ b/src/Contract/Deprecation/DeprecationInterface.php @@ -0,0 +1,21 @@ + Date: Sun, 6 Aug 2017 19:49:19 +0200 Subject: [PATCH 06/22] [NodeTraverser] add ParentClassToTrait refactor --- ...eprecatedParentClassToTraitNodeVisitor.php | 65 +++++++++++++++++++ .../Test.php | 16 +++++ .../correct/correct.php.inc | 6 ++ .../correct/correct2.php.inc | 7 ++ .../wrong/wrong.php.inc | 5 ++ .../wrong/wrong2.php.inc | 6 ++ 6 files changed, 105 insertions(+) create mode 100644 src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct.php.inc create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct2.php.inc create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/wrong/wrong.php.inc create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/wrong/wrong2.php.inc diff --git a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php new file mode 100644 index 00000000000..5664082e8eb --- /dev/null +++ b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php @@ -0,0 +1,65 @@ +isCandidate($node)) { + $this->refactor($node); + return NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + + return null; + } + + private function isCandidate(Node $node): bool + { + if ($node instanceof Node\Stmt\Class_) { + if (! $node->extends) { + return false; + } + + $parentClassName = (string) $node->extends; + if ($parentClassName !== $this->getParentClassName()) { + return false; + } + + return true; + } + + return false; + } + + private function refactor(Node\Stmt\Class_ $classNode) + { + // remove parent class + $classNode->extends = null; + + // add new trait + $nameParts = explode('\\', $this->getTraitName()); + $classNode->stmts[] = new TraitUse([ + new FullyQualified($nameParts) + ]); + } +} diff --git a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php new file mode 100644 index 00000000000..a7a8f29ac9a --- /dev/null +++ b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php @@ -0,0 +1,16 @@ +doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong.php.inc', + __DIR__ . '/correct/correct.php.inc' + ); + } +} diff --git a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct.php.inc b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct.php.inc new file mode 100644 index 00000000000..10e922d412f --- /dev/null +++ b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct.php.inc @@ -0,0 +1,6 @@ + Date: Sun, 6 Aug 2017 19:52:50 +0200 Subject: [PATCH 07/22] fix cs --- .../DeprecatedParentClassToTraitNodeVisitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php index 5664082e8eb..fd062c67484 100644 --- a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php +++ b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php @@ -51,7 +51,7 @@ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract return false; } - private function refactor(Node\Stmt\Class_ $classNode) + private function refactor(Node\Stmt\Class_ $classNode): void { // remove parent class $classNode->extends = null; From 5d7c589533f247654d473ef6f9f3be26b2e0aaca Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 6 Aug 2017 23:11:50 +0200 Subject: [PATCH 08/22] cs fixes --- easy-coding-standard.neon | 16 ++++++++-------- .../GetterToPropertyNodeVisitor.php | 11 +++++------ .../DeprecatedParentClassToTraitNodeVisitor.php | 5 +++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/easy-coding-standard.neon b/easy-coding-standard.neon index c78cfa5ad25..9b985f054ce 100644 --- a/easy-coding-standard.neon +++ b/easy-coding-standard.neon @@ -5,11 +5,13 @@ includes: checkers: # Slevomat - - SlevomatCodingStandard\Sniffs\ControlStructures\DisallowEqualOperatorsSniff - SlevomatCodingStandard\Sniffs\ControlStructures\YodaComparisonSniff - SlevomatCodingStandard\Sniffs\Exceptions\DeadCatchSniff - SlevomatCodingStandard\Sniffs\Exceptions\ReferenceThrowableOnlySniff - - SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff + SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff: + allowPartialUses: false + allowFullyQualifiedNameForCollidingClasses: false + allowFullyQualifiedGlobalClasses: true - SlevomatCodingStandard\Sniffs\Classes\UnusedPrivateElementsSniff # Files @@ -22,9 +24,9 @@ checkers: # Code Analysis - PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\EmptyStatementSniff PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff: - absoluteComplexity: 10 + absoluteComplexity: 5 PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff: - absoluteNestingLevel: 5 + absoluteNestingLevel: 2 # Naming Conventions - PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff @@ -43,13 +45,10 @@ checkers: PhpCsFixer\Fixer\Operator\ConcatSpaceFixer: spacing: one - PhpCsFixer\Fixer\ClassNotation\OrderedClassElementsFixer - - PhpCsFixer\Fixer\LanguageConstruct\DirConstantFixer - - PhpCsFixer\Fixer\CastNotation\ModernizeTypesCastingFixer - PhpCsFixer\Fixer\Semicolon\SemicolonAfterInstructionFixer - PhpCsFixer\Fixer\Operator\NotOperatorWithSuccessorSpaceFixer - PhpCsFixer\Fixer\ControlStructure\NoUselessElseFixer - PhpCsFixer\Fixer\ReturnNotation\NoUselessReturnFixer - - PhpCsFixer\Fixer\LanguageConstruct\CombineConsecutiveUnsetsFixer - PhpCsFixer\Fixer\Strict\StrictComparisonFixer PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer: annotations: @@ -62,7 +61,8 @@ checkers: # new since PhpCsFixer 2.2-2.4 - PhpCsFixer\Fixer\Phpdoc\PhpdocReturnSelfReferenceFixer - - PhpCsFixer\Fixer\LanguageConstruct\IsNullFixer + PhpCsFixer\Fixer\LanguageConstruct\IsNullFixer: + use_yoda_style: false - PhpCsFixer\Fixer\Basic\NonPrintableCharacterFixer - PhpCsFixer\Fixer\Phpdoc\PhpdocTypesOrderFixer - PhpCsFixer\Fixer\Comment\SingleLineCommentStyleFixer \ No newline at end of file diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php index caaf9e7c573..18384bd4c7f 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php @@ -8,6 +8,7 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Scalar\String_; +use PhpParser\Node\Stmt\Class_; use PhpParser\NodeVisitorAbstract; use Rector\Builder\Class_\ClassPropertyCollector; use Rector\Builder\Kernel\ServiceFromKernelResolver; @@ -60,7 +61,7 @@ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract public function beforeTraverse(array $nodes): ?array { foreach ($nodes as $node) { - if ($node instanceof Node\Stmt\Class_) { + if ($node instanceof Class_) { $this->className = (string) $node->name; } } @@ -96,11 +97,9 @@ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract { // $var = $this->get('some_service'); // $var = $this->get('some_service')->getData(); - if ($node instanceof Assign) { - if ($node->expr instanceof MethodCall || $node->var instanceof MethodCall) { - if ($this->isContainerGetCall($node->expr)) { - return true; - } + if ($node instanceof Assign && ($node->expr instanceof MethodCall || $node->var instanceof MethodCall)) { + if ($this->isContainerGetCall($node->expr)) { + return true; } } diff --git a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php index fd062c67484..2a4c9c214e1 100644 --- a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php +++ b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php @@ -4,6 +4,7 @@ namespace Rector\NodeVisitor\UpgradeDeprecation; use PhpParser\Node; use PhpParser\Node\Name\FullyQualified; +use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\TraitUse; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; @@ -35,7 +36,7 @@ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract private function isCandidate(Node $node): bool { - if ($node instanceof Node\Stmt\Class_) { + if ($node instanceof Class_) { if (! $node->extends) { return false; } @@ -51,7 +52,7 @@ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract return false; } - private function refactor(Node\Stmt\Class_ $classNode): void + private function refactor(Class_ $classNode): void { // remove parent class $classNode->extends = null; From d81801447767228b814f17794f64a2d2f487c102 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 6 Aug 2017 23:24:58 +0200 Subject: [PATCH 09/22] StatementGlue added --- src/Builder/ConstructorMethodBuilder.php | 28 +++------ src/Builder/PropertyBuilder.php | 41 +++--------- src/Builder/StatementGlue.php | 63 +++++++++++++++++++ ...eprecatedParentClassToTraitNodeVisitor.php | 23 ++++++- .../Test.php | 8 ++- 5 files changed, 105 insertions(+), 58 deletions(-) create mode 100644 src/Builder/StatementGlue.php diff --git a/src/Builder/ConstructorMethodBuilder.php b/src/Builder/ConstructorMethodBuilder.php index 1f4ddd8a6fe..e6e3660d1d1 100644 --- a/src/Builder/ConstructorMethodBuilder.php +++ b/src/Builder/ConstructorMethodBuilder.php @@ -2,7 +2,6 @@ namespace Rector\Builder; -use Nette\Utils\Arrays; use PhpParser\Builder\Method; use PhpParser\Builder\Param; use PhpParser\BuilderFactory; @@ -23,10 +22,16 @@ final class ConstructorMethodBuilder */ private $builderFactory; - public function __construct(Parser $parser, BuilderFactory $builderFactory) + /** + * @var StatementGlue + */ + private $statementGlue; + + public function __construct(Parser $parser, BuilderFactory $builderFactory, StatementGlue $statementGlue) { $this->parser = $parser; $this->builderFactory = $builderFactory; + $this->statementGlue = $statementGlue; } public function addPropertyAssignToClass(Class_ $classNode, string $propertyType, string $propertyName): void @@ -50,7 +55,7 @@ final class ConstructorMethodBuilder ->addParam($this->createParameter($propertyType, $propertyName)) ->addStmts($assign); - $this->addAsFirstMethod($classNode, $constructorMethod->getNode()); + $this->statementGlue->addAsFirstMethod($classNode, $constructorMethod->getNode()); } private function createParameter(string $propertyType, string $propertyName): Param @@ -70,21 +75,4 @@ final class ConstructorMethodBuilder $propertyName )); } - - private function addAsFirstMethod(Class_ $classNode, ClassMethod $constructorMethod): void - { - foreach ($classNode->stmts as $key => $classElementNode) { - if ($classElementNode instanceof ClassMethod) { - Arrays::insertBefore( - $classNode->stmts, - $key, - ['before_' . $key => $constructorMethod] - ); - - return; - } - } - - $classNode->stmts[] = $constructorMethod; - } } diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index f0f92634551..a0237e9b53a 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -2,11 +2,9 @@ namespace Rector\Builder; -use Nette\Utils\Arrays; use PhpParser\BuilderFactory; use PhpParser\Comment\Doc; use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; final class PropertyBuilder @@ -16,45 +14,22 @@ final class PropertyBuilder */ private $builderFactory; - public function __construct(BuilderFactory $builderFactory) + /** + * @var StatementGlue + */ + private $statementGlue; + + public function __construct(BuilderFactory $builderFactory, StatementGlue $statementGlue) { $this->builderFactory = $builderFactory; + $this->statementGlue = $statementGlue; } public function addPropertyToClass(Class_ $classNode, string $propertyType, string $propertyName): void { $propertyNode = $this->buildPrivatePropertyNode($propertyType, $propertyName); - // add before first method - foreach ($classNode->stmts as $key => $classElementNode) { - if ($classElementNode instanceof ClassMethod) { - Arrays::insertBefore( - $classNode->stmts, - $key, - ['before_' . $key => $propertyNode] - ); - - return; - } - } - - // or after last property - $previousElement = null; - foreach ($classNode->stmts as $key => $classElementNode) { - if ($previousElement instanceof Property && ! $classElementNode instanceof Property) { - Arrays::insertBefore( - $classNode->stmts, - $key, - ['before_' . $key => $propertyNode] - ); - - return; - } - - $previousElement = $classElementNode; - } - - $classNode->stmts[] = $propertyNode; + $this->statementGlue->addAsFirstMethod($classNode, $propertyNode); } private function buildPrivatePropertyNode(string $propertyType, string $propertyName): Property diff --git a/src/Builder/StatementGlue.php b/src/Builder/StatementGlue.php new file mode 100644 index 00000000000..56979223555 --- /dev/null +++ b/src/Builder/StatementGlue.php @@ -0,0 +1,63 @@ +stmts as $key => $classElementNode) { + if ($classElementNode instanceof ClassMethod) { + $this->insertBefore($classNode, $node, $key); + + return; + } + } + + $previousElement = null; + foreach ($classNode->stmts as $key => $classElementNode) { + if ($previousElement instanceof Property && ! $classElementNode instanceof Property) { + $this->insertBefore($classNode, $node, $key); + + return; + } + + $previousElement = $classElementNode; + } + + $classNode->stmts[] = $node; + } + + public function addAsFirstTrait(Class_ $classNode, TraitUse $traitUse): void + { + foreach ($classNode->stmts as $key => $classElementNode) { + if ($classElementNode instanceof TraitUse) { + $this->insertBefore($classNode, $traitUse, $key); + + return; + } + } + + $classNode->stmts[] = $traitUse; + } + + /** + * @param int|string $key + */ + private function insertBefore(Class_ $classNode, Node $node, $key): void + { + Arrays::insertBefore($classNode->stmts, $key, [ + 'before_' . $key => $node + ]); + } +} diff --git a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php index 2a4c9c214e1..2b791e3558d 100644 --- a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php +++ b/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php @@ -8,12 +8,23 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\TraitUse; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; +use Rector\Builder\StatementGlue; /** * Reflects @link https://doc.nette.org/en/2.4/migration-2-4#toc-nette-smartobject */ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract { + /** + * @var StatementGlue + */ + private $statementGlue; + + public function __construct(StatementGlue $statementGlue) + { + $this->statementGlue = $statementGlue; + } + public function getParentClassName(): string { return 'Nette\Object'; @@ -57,9 +68,15 @@ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract // remove parent class $classNode->extends = null; - // add new trait - $nameParts = explode('\\', $this->getTraitName()); - $classNode->stmts[] = new TraitUse([ + $traitUseNode = $this->createTraitUse($this->getTraitName()); + $this->statementGlue->addAsFirstTrait($classNode, $traitUseNode); + } + + private function createTraitUse(string $traitName): TraitUse + { + $nameParts = explode('\\', $traitName); + + return new TraitUse([ new FullyQualified($nameParts) ]); } diff --git a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php index a7a8f29ac9a..1fbe121cd97 100644 --- a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php +++ b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php @@ -8,9 +8,13 @@ final class Test extends AbstractReconstructorTestCase { public function test(): void { + // $this->doTestFileMatchesExpectedContent( + // __DIR__ . '/wrong/wrong.php.inc', + // __DIR__ . '/correct/correct.php.inc' + // ); $this->doTestFileMatchesExpectedContent( - __DIR__ . '/wrong/wrong.php.inc', - __DIR__ . '/correct/correct.php.inc' + __DIR__ . '/wrong/wrong2.php.inc', + __DIR__ . '/correct/correct2.php.inc' ); } } From 61c7ef9de08df141cbb52aefd78f73c9d04e67bb Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 6 Aug 2017 23:37:10 +0200 Subject: [PATCH 10/22] improve tests --- src/Application/FileProcessor.php | 6 +++--- src/Builder/StatementGlue.php | 19 +++++++++++++------ ...ceReplaceDeprecatedConstantNodeVisitor.php | 13 ------------- .../Test.php | 12 ++++++++---- .../correct/correct3.php.inc | 7 +++++++ .../wrong/wrong3.php.inc | 6 ++++++ 6 files changed, 37 insertions(+), 26 deletions(-) create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct3.php.inc create mode 100644 tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/wrong/wrong3.php.inc diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index bffc03fda1a..4b867050555 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -18,7 +18,7 @@ final class FileProcessor /** * @var FormatPerservingPrinter */ - private $codeStyledPrinter; + private $formatPerservingPrinter; /** * @var NodeTraverser @@ -37,7 +37,7 @@ final class FileProcessor NodeTraverser $nodeTraverser ) { $this->parser = $parser; - $this->codeStyledPrinter = $codeStyledPrinter; + $this->formatPerservingPrinter = $codeStyledPrinter; $this->nodeTraverser = $nodeTraverser; $this->lexer = $lexer; } @@ -66,7 +66,7 @@ final class FileProcessor $newStmts = $this->nodeTraverser->traverse($oldStmts); - $this->codeStyledPrinter->printToFile($file, $newStmts, $oldStmts, $oldTokens); + $this->formatPerservingPrinter->printToFile($file, $newStmts, $oldStmts, $oldTokens); } /** diff --git a/src/Builder/StatementGlue.php b/src/Builder/StatementGlue.php index 56979223555..e3d6dc067a0 100644 --- a/src/Builder/StatementGlue.php +++ b/src/Builder/StatementGlue.php @@ -38,17 +38,24 @@ final class StatementGlue $classNode->stmts[] = $node; } - public function addAsFirstTrait(Class_ $classNode, TraitUse $traitUse): void + public function addAsFirstTrait(Class_ $classNode, Node $node): void { - foreach ($classNode->stmts as $key => $classElementNode) { - if ($classElementNode instanceof TraitUse) { - $this->insertBefore($classNode, $traitUse, $key); + $this->addStatementToClassBeforeTypes($classNode, $node, TraitUse::class, Property::class); + } - return; + private function addStatementToClassBeforeTypes(Class_ $classNode, Node $node, string ...$types): void + { + foreach ($types as $type) { + foreach ($classNode->stmts as $key => $classElementNode) { + if (is_a($classElementNode, $type, true)) { + $this->insertBefore($classNode, $node, $key); + + return; + } } } - $classNode->stmts[] = $traitUse; + $classNode->stmts[] = $node; } /** diff --git a/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php index 013a6ba0a1d..e2182e9b7d3 100644 --- a/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php +++ b/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php @@ -15,19 +15,6 @@ abstract class AbstraceReplaceDeprecatedConstantNodeVisitor extends NodeVisitorA abstract public function getNewConstantName(): string; - /** - * Return value semantics: - * * null - * => $node stays as-is - * * NodeTraverser::DONT_TRAVERSE_CHILDREN - * => Children of $node are not traversed. $node stays as-is - * * NodeTraverser::STOP_TRAVERSAL - * => Traversal is aborted. $node stays as-is - * * otherwise - * => $node is set to the return value. - * - * @return null|int|Node - */ public function enterNode(Node $node): ?int { if ($this->isCandidate($node)) { diff --git a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php index 1fbe121cd97..840aeeee6ff 100644 --- a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php +++ b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php @@ -8,13 +8,17 @@ final class Test extends AbstractReconstructorTestCase { public function test(): void { - // $this->doTestFileMatchesExpectedContent( - // __DIR__ . '/wrong/wrong.php.inc', - // __DIR__ . '/correct/correct.php.inc' - // ); + $this->doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong.php.inc', + __DIR__ . '/correct/correct.php.inc' + ); $this->doTestFileMatchesExpectedContent( __DIR__ . '/wrong/wrong2.php.inc', __DIR__ . '/correct/correct2.php.inc' ); + $this->doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong3.php.inc', + __DIR__ . '/correct/correct3.php.inc' + ); } } diff --git a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct3.php.inc b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct3.php.inc new file mode 100644 index 00000000000..3b9cd459f21 --- /dev/null +++ b/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/correct/correct3.php.inc @@ -0,0 +1,7 @@ + Date: Mon, 7 Aug 2017 15:53:52 +0200 Subject: [PATCH 11/22] misc --- .travis.yml | 4 +--- easy-coding-standard.neon | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 179a4f35d82..bed0e431da0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,5 @@ after_script: php coveralls.phar --verbose fi -# do not send success notifications, they have no value notifications: - email: - on_success: never + email: never diff --git a/easy-coding-standard.neon b/easy-coding-standard.neon index 9b985f054ce..e7be08bf21c 100644 --- a/easy-coding-standard.neon +++ b/easy-coding-standard.neon @@ -26,7 +26,7 @@ checkers: PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff: absoluteComplexity: 5 PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff: - absoluteNestingLevel: 2 + absoluteNestingLevel: 3 # Naming Conventions - PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff From bcc02f678c4fb07290f7c565878daaf72d5efb9e Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 7 Aug 2017 17:27:04 +0200 Subject: [PATCH 12/22] move NodeVisitor to Rector, add AbstractRector --- src/Contract/Rector/RectorInterface.php | 15 +++++++ src/Rector/AbstractRector.php | 22 ++++++++++ .../Contrib/Nette/FormCallbackRector.php | 42 +++++++++++++++++++ .../Nette/NetteObjectToSmartTraitRector.php} | 41 +++++++----------- .../Contrib/Nette/FormCallbackRector/Test.php | 16 +++++++ .../correct/correct-better.php.inc | 15 +++++++ .../correct/correct.php.inc | 13 ++++++ .../FormCallbackRector/wrong/wrong.php.inc | 13 ++++++ .../NetteObjectToSmartTraitRector}/Test.php | 2 +- .../correct/correct.php.inc | 0 .../correct/correct2.php.inc | 0 .../correct/correct3.php.inc | 0 .../wrong/wrong.php.inc | 0 .../wrong/wrong2.php.inc | 0 .../wrong/wrong3.php.inc | 0 15 files changed, 153 insertions(+), 26 deletions(-) create mode 100644 src/Contract/Rector/RectorInterface.php create mode 100644 src/Rector/AbstractRector.php create mode 100644 src/Rector/Contrib/Nette/FormCallbackRector.php rename src/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php => Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php} (54%) create mode 100644 tests/Rector/Contrib/Nette/FormCallbackRector/Test.php create mode 100644 tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct-better.php.inc create mode 100644 tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct.php.inc create mode 100644 tests/Rector/Contrib/Nette/FormCallbackRector/wrong/wrong.php.inc rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/Test.php (87%) rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/correct/correct.php.inc (100%) rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/correct/correct2.php.inc (100%) rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/correct/correct3.php.inc (100%) rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/wrong/wrong.php.inc (100%) rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/wrong/wrong2.php.inc (100%) rename tests/{NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor => Rector/Contrib/Nette/NetteObjectToSmartTraitRector}/wrong/wrong3.php.inc (100%) diff --git a/src/Contract/Rector/RectorInterface.php b/src/Contract/Rector/RectorInterface.php new file mode 100644 index 00000000000..e060860395d --- /dev/null +++ b/src/Contract/Rector/RectorInterface.php @@ -0,0 +1,15 @@ +isCandidate($node)) { + $this->refactor($node); + return NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + + return null; + } +} diff --git a/src/Rector/Contrib/Nette/FormCallbackRector.php b/src/Rector/Contrib/Nette/FormCallbackRector.php new file mode 100644 index 00000000000..b129529d076 --- /dev/null +++ b/src/Rector/Contrib/Nette/FormCallbackRector.php @@ -0,0 +1,42 @@ +isCandidate($node)) { + dump($node); // get next node! + die; + + $this->refactor($node); + return NodeTraverser::DONT_TRAVERSE_CHILDREN; + } + + return null; + } + + private function isCandidate(Node $node): bool + { + return $node instanceof Node\Expr\PropertyFetch; + } +} diff --git a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php similarity index 54% rename from src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php rename to src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php index 2b791e3558d..01eb3bedc49 100644 --- a/src/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor.php +++ b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php @@ -1,19 +1,19 @@ statementGlue = $statementGlue; } - public function getParentClassName(): string + public function getSetName(): string { - return 'Nette\Object'; + return SetNames::NETTE; } - public function getTraitName(): string + public function sinceVersion(): float { - return 'Nette\SmartObject'; + return 2.2; } - public function enterNode(Node $node): ?int - { - if ($this->isCandidate($node)) { - $this->refactor($node); - return NodeTraverser::DONT_TRAVERSE_CHILDREN; - } - - return null; - } - - private function isCandidate(Node $node): bool + public function isCandidate(Node $node): bool { if ($node instanceof Class_) { if (! $node->extends) { @@ -53,7 +43,7 @@ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract } $parentClassName = (string) $node->extends; - if ($parentClassName !== $this->getParentClassName()) { + if ($parentClassName !== 'Nette\Object') { return false; } @@ -63,21 +53,22 @@ final class DeprecatedParentClassToTraitNodeVisitor extends NodeVisitorAbstract return false; } - private function refactor(Class_ $classNode): void + /** + * @param Class_ $classNode + */ + public function refactor($classNode): void { // remove parent class $classNode->extends = null; - $traitUseNode = $this->createTraitUse($this->getTraitName()); + $traitUseNode = $this->createTraitUse('Nette\SmartObject'); $this->statementGlue->addAsFirstTrait($classNode, $traitUseNode); } private function createTraitUse(string $traitName): TraitUse { - $nameParts = explode('\\', $traitName); - return new TraitUse([ - new FullyQualified($nameParts) + new FullyQualified($traitName) ]); } } diff --git a/tests/Rector/Contrib/Nette/FormCallbackRector/Test.php b/tests/Rector/Contrib/Nette/FormCallbackRector/Test.php new file mode 100644 index 00000000000..79c92ba1a6d --- /dev/null +++ b/tests/Rector/Contrib/Nette/FormCallbackRector/Test.php @@ -0,0 +1,16 @@ +doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong.php.inc', + __DIR__ . '/correct/correct.php.inc' + ); + } +} diff --git a/tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct-better.php.inc b/tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct-better.php.inc new file mode 100644 index 00000000000..d4d49b03530 --- /dev/null +++ b/tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct-better.php.inc @@ -0,0 +1,15 @@ +onSuccess[] = function (Form $form) { + $this->someMethod($form); + }; + + return $form; + } +} diff --git a/tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct.php.inc b/tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct.php.inc new file mode 100644 index 00000000000..a39a6bfc0b6 --- /dev/null +++ b/tests/Rector/Contrib/Nette/FormCallbackRector/correct/correct.php.inc @@ -0,0 +1,13 @@ +onSuccess[] = [$this, 'someMethod']; + + return $form; + } +} diff --git a/tests/Rector/Contrib/Nette/FormCallbackRector/wrong/wrong.php.inc b/tests/Rector/Contrib/Nette/FormCallbackRector/wrong/wrong.php.inc new file mode 100644 index 00000000000..bce32d4aee7 --- /dev/null +++ b/tests/Rector/Contrib/Nette/FormCallbackRector/wrong/wrong.php.inc @@ -0,0 +1,13 @@ +onSuccess[] = $this->someMethod; + + return $form; + } +} diff --git a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php similarity index 87% rename from tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php rename to tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php index 840aeeee6ff..ea2b3c430b9 100644 --- a/tests/NodeVisitor/UpgradeDeprecation/DeprecatedParentClassToTraitNodeVisitor/Test.php +++ b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php @@ -1,6 +1,6 @@ Date: Mon, 7 Aug 2017 17:41:58 +0200 Subject: [PATCH 13/22] refactor NodeVisitor to Rectors --- ...ceReplaceDeprecatedConstantNodeVisitor.php | 49 ------------------- .../Nette/NetteObjectToSmartTraitRector.php | 2 +- .../RemoveConfiguratorConstantsRector.php | 49 +++++++++++++++++++ .../PHPUnit/AbstractReconstructorTestCase.php | 2 +- .../ReplaceOldConstantNodeVisitor.php | 23 --------- .../Test.php | 2 +- .../correct/correct.php.inc | 0 .../wrong/wrong.php.inc | 0 tests/config/services.yml | 6 --- 9 files changed, 52 insertions(+), 81 deletions(-) delete mode 100644 src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php create mode 100644 src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php delete mode 100644 tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php rename tests/{NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor => Rector/Contrib/Nette/RemoveConfiguratorConstantsRector}/Test.php (79%) rename tests/{NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor => Rector/Contrib/Nette/RemoveConfiguratorConstantsRector}/correct/correct.php.inc (100%) rename tests/{NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor => Rector/Contrib/Nette/RemoveConfiguratorConstantsRector}/wrong/wrong.php.inc (100%) delete mode 100644 tests/config/services.yml diff --git a/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php b/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php deleted file mode 100644 index e2182e9b7d3..00000000000 --- a/src/NodeVisitor/UpgradeDeprecation/AbstraceReplaceDeprecatedConstantNodeVisitor.php +++ /dev/null @@ -1,49 +0,0 @@ -isCandidate($node)) { - $this->refactor($node); - return NodeTraverser::DONT_TRAVERSE_CHILDREN; - } - - return null; - } - - private function isCandidate(Node $node): bool - { - if ($node instanceof ClassConstFetch) { - if ((string) $node->class !== $this->getClassName()) { - return false; - } - - if ((string) $node->name !== $this->getOldConstantName()) { - return false; - } - - return true; - } - - return false; - } - - private function refactor(ClassConstFetch $classConstFetchNode): void - { - $classConstFetchNode->name->name = $this->getNewConstantName(); - } -} diff --git a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php index 01eb3bedc49..82c99655ce0 100644 --- a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php +++ b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php @@ -11,7 +11,7 @@ use Rector\Deprecation\SetNames; use Rector\Rector\AbstractRector; /** - * Reflects @link https://doc.nette.org/en/2.4/migration-2-4#toc-nette-smartobject + * Covers https://doc.nette.org/en/2.4/migration-2-4#toc-nette-smartobject */ final class NetteObjectToSmartTraitRector extends AbstractRector { diff --git a/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php b/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php new file mode 100644 index 00000000000..55614ea0739 --- /dev/null +++ b/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php @@ -0,0 +1,49 @@ +class !== 'Nette\Configurator') { + return false; + } + + if (! in_array((string) $node->name, ['DEVELOPMENT', 'PRODUCTION'], true)) { + return false; + } + + return true; + } + + return false; + } + + /** + * @param ClassConstFetch $classConstFetchNode + */ + public function refactor($classConstFetchNode): void + { + dump($classConstFetchNode->name->name); + die; + + $classConstFetchNode->name->name = $this->getNewConstantName(); + } + + public function getSetName(): string + { + return SetNames::NETTE; + } + + public function sinceVersion(): float + { + return 2.3; + } +} diff --git a/src/Testing/PHPUnit/AbstractReconstructorTestCase.php b/src/Testing/PHPUnit/AbstractReconstructorTestCase.php index f3dcce41136..730ad2629e3 100644 --- a/src/Testing/PHPUnit/AbstractReconstructorTestCase.php +++ b/src/Testing/PHPUnit/AbstractReconstructorTestCase.php @@ -22,7 +22,7 @@ abstract class AbstractReconstructorTestCase extends TestCase protected function setUp(): void { - $this->container = (new ContainerFactory)->createWithConfig(__DIR__ . '/../../../tests/config/services.yml'); + $this->container = (new ContainerFactory)->create(); $this->fileReconstructor = $this->container->get(FileReconstructor::class); } diff --git a/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php b/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php deleted file mode 100644 index c9e5e5bcece..00000000000 --- a/tests/NodeVisitor/UpgradeDeprecation/ReplaceDeprecatedConstantNodeVisitor/ReplaceOldConstantNodeVisitor.php +++ /dev/null @@ -1,23 +0,0 @@ - Date: Mon, 7 Aug 2017 17:52:18 +0200 Subject: [PATCH 14/22] wip --- src/Contract/Rector/RectorInterface.php | 2 +- src/Rector/AbstractRector.php | 10 ++++++++-- src/Rector/Contrib/Nette/FormCallbackRector.php | 1 + .../Contrib/Nette/NetteObjectToSmartTraitRector.php | 4 +++- .../Nette/RemoveConfiguratorConstantsRector.php | 13 ++++++++----- .../correct/correct.php.inc | 2 +- .../wrong/wrong.php.inc | 4 +++- 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Contract/Rector/RectorInterface.php b/src/Contract/Rector/RectorInterface.php index e060860395d..9be5a353d4b 100644 --- a/src/Contract/Rector/RectorInterface.php +++ b/src/Contract/Rector/RectorInterface.php @@ -11,5 +11,5 @@ interface RectorInterface /** * @param Node $node */ - public function refactor($node): void; + public function refactor($node): ?Node; } diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index dcdeb515d6d..48ca7a5870e 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -10,10 +10,16 @@ use Rector\Contract\Rector\RectorInterface; abstract class AbstractRector extends NodeVisitorAbstract implements DeprecationInterface, RectorInterface { - public function enterNode(Node $node): ?int + /** + * @return int|null|Node + */ + public function enterNode(Node $node) { if ($this->isCandidate($node)) { - $this->refactor($node); + if ($newNode = $this->refactor($node)) { + return $newNode; + } + return NodeTraverser::DONT_TRAVERSE_CHILDREN; } diff --git a/src/Rector/Contrib/Nette/FormCallbackRector.php b/src/Rector/Contrib/Nette/FormCallbackRector.php index b129529d076..5a843afce0f 100644 --- a/src/Rector/Contrib/Nette/FormCallbackRector.php +++ b/src/Rector/Contrib/Nette/FormCallbackRector.php @@ -25,6 +25,7 @@ final class FormCallbackRector extends NodeVisitorAbstract implements Deprecatio public function enterNode(Node $node): ?int { if ($this->isCandidate($node)) { + return false; dump($node); // get next node! die; diff --git a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php index 82c99655ce0..26c26a0b421 100644 --- a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php +++ b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php @@ -56,13 +56,15 @@ final class NetteObjectToSmartTraitRector extends AbstractRector /** * @param Class_ $classNode */ - public function refactor($classNode): void + public function refactor($classNode): ?Node { // remove parent class $classNode->extends = null; $traitUseNode = $this->createTraitUse('Nette\SmartObject'); $this->statementGlue->addAsFirstTrait($classNode, $traitUseNode); + + return null; } private function createTraitUse(string $traitName): TraitUse diff --git a/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php b/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php index 55614ea0739..a2c2eb26bde 100644 --- a/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php +++ b/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php @@ -6,13 +6,16 @@ use PhpParser\Node; use PhpParser\Node\Expr\ClassConstFetch; use Rector\Deprecation\SetNames; use Rector\Rector\AbstractRector; +use PhpParser\Node\Scalar\String_; final class RemoveConfiguratorConstantsRector extends AbstractRector { public function isCandidate(Node $node): bool { if ($node instanceof ClassConstFetch) { - if ((string) $node->class !== 'Nette\Configurator') { + // @todo: check FQN namespace + $className = (string) $node->class; + if (! in_array($className, ['Nette\Configurator', 'Configurator'], true)) { return false; } @@ -29,12 +32,12 @@ final class RemoveConfiguratorConstantsRector extends AbstractRector /** * @param ClassConstFetch $classConstFetchNode */ - public function refactor($classConstFetchNode): void + public function refactor($classConstFetchNode): ?Node { - dump($classConstFetchNode->name->name); - die; + $constantName = (string) $classConstFetchNode->name; + $string = strtolower($constantName); - $classConstFetchNode->name->name = $this->getNewConstantName(); + return new String_($string); } public function getSetName(): string diff --git a/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc b/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc index 5cf52e94219..49cee4c3dd0 100644 --- a/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc +++ b/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc @@ -4,6 +4,6 @@ class ClassWithExternalConstant { public function getValue() { - return ClassWithConstants::NEW_CONSTANT; + return 'development'; } } diff --git a/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/wrong/wrong.php.inc b/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/wrong/wrong.php.inc index 76c747b641a..f1abc503dd2 100644 --- a/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/wrong/wrong.php.inc +++ b/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/wrong/wrong.php.inc @@ -1,9 +1,11 @@ Date: Mon, 7 Aug 2017 23:12:10 +0200 Subject: [PATCH 15/22] fixes --- src/Application/FileProcessor.php | 2 -- src/Parser/LexerFactory.php | 4 +--- src/Parser/ParserFactory.php | 16 +++++++++++++--- src/Printer/FormatPerservingPrinter.php | 1 + .../Nette/NetteObjectToSmartTraitRector.php | 2 +- src/Testing/Application/FileReconstructor.php | 4 ---- src/config/services.yml | 1 + .../Nette/NetteObjectToSmartTraitRector/Test.php | 16 ++++++++-------- .../correct/correct.php.inc | 2 ++ 9 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index 4b867050555..71a8d8a3899 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -61,9 +61,7 @@ final class FileProcessor } $oldStmts = $this->cloneArrayOfObjects($oldStmts); - $oldTokens = $this->lexer->getTokens(); - $newStmts = $this->nodeTraverser->traverse($oldStmts); $this->formatPerservingPrinter->printToFile($file, $newStmts, $oldStmts, $oldTokens); diff --git a/src/Parser/LexerFactory.php b/src/Parser/LexerFactory.php index f3028f4ef28..4e2d9698424 100644 --- a/src/Parser/LexerFactory.php +++ b/src/Parser/LexerFactory.php @@ -15,9 +15,7 @@ final class LexerFactory { return new Emulative([ 'usedAttributes' => [ - 'comments', - 'startLine', 'endLine', - 'startTokenPos', 'endTokenPos', + 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', ], ]); } diff --git a/src/Parser/ParserFactory.php b/src/Parser/ParserFactory.php index 8ad27b9b9d0..ab981dac4de 100644 --- a/src/Parser/ParserFactory.php +++ b/src/Parser/ParserFactory.php @@ -13,14 +13,24 @@ final class ParserFactory */ private $lexer; - public function __construct(Lexer $lexer) + /** + * @var NikicParserFactory + */ + private $nikicParserFactory; + + public function __construct(Lexer $lexer, NikicParserFactory $nikicParserFactory) { $this->lexer = $lexer; + $this->nikicParserFactory = $nikicParserFactory; } public function create(): Parser { - $nikicParserFactory = new NikicParserFactory; - return $nikicParserFactory->create(NikicParserFactory::PREFER_PHP7, $this->lexer); + return $this->nikicParserFactory->create(NikicParserFactory::PREFER_PHP7, $this->lexer, [ + 'useIdentifierNodes' => true, + 'useConsistentVariableNodes' => true, + 'useExpressionStatements' => true, + 'useNopStatements' => false, + ]); } } diff --git a/src/Printer/FormatPerservingPrinter.php b/src/Printer/FormatPerservingPrinter.php index ca6a78676e3..8b046b22298 100644 --- a/src/Printer/FormatPerservingPrinter.php +++ b/src/Printer/FormatPerservingPrinter.php @@ -4,6 +4,7 @@ namespace Rector\Printer; use PhpParser\PrettyPrinter\Standard; use SplFileInfo; +use Tracy\Debugger; final class FormatPerservingPrinter { diff --git a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php index 26c26a0b421..3d9f6452b55 100644 --- a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php +++ b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php @@ -64,7 +64,7 @@ final class NetteObjectToSmartTraitRector extends AbstractRector $traitUseNode = $this->createTraitUse('Nette\SmartObject'); $this->statementGlue->addAsFirstTrait($classNode, $traitUseNode); - return null; + return $classNode; } private function createTraitUse(string $traitName): TraitUse diff --git a/src/Testing/Application/FileReconstructor.php b/src/Testing/Application/FileReconstructor.php index 5ab8f87ed92..92e1ad699d5 100644 --- a/src/Testing/Application/FileReconstructor.php +++ b/src/Testing/Application/FileReconstructor.php @@ -59,10 +59,6 @@ final class FileReconstructor $oldTokens = $this->lexer->getTokens(); $newStmts = $this->nodeTraverser->traverse($oldStmts); - if (! $this->stateHolder->isAfterTraverseCalled()) { - [$newStmts, $oldStmts] = [$oldStmts, $newStmts]; - } - return $this->codeStyledPrinter->printToString($newStmts, $oldStmts, $oldTokens); } } diff --git a/src/config/services.yml b/src/config/services.yml index 3642becdbe5..9a8a0e4bbc6 100644 --- a/src/config/services.yml +++ b/src/config/services.yml @@ -22,6 +22,7 @@ services: # Traverser PhpParser\NodeTraverser: ~ + PhpParser\ParserFactory: ~ # Printer PhpParser\NodeVisitor\CloningVisitor: ~ PhpParser\PrettyPrinter\Standard: ~ diff --git a/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php index ea2b3c430b9..5106cc5f85d 100644 --- a/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php +++ b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php @@ -12,13 +12,13 @@ final class Test extends AbstractReconstructorTestCase __DIR__ . '/wrong/wrong.php.inc', __DIR__ . '/correct/correct.php.inc' ); - $this->doTestFileMatchesExpectedContent( - __DIR__ . '/wrong/wrong2.php.inc', - __DIR__ . '/correct/correct2.php.inc' - ); - $this->doTestFileMatchesExpectedContent( - __DIR__ . '/wrong/wrong3.php.inc', - __DIR__ . '/correct/correct3.php.inc' - ); +// $this->doTestFileMatchesExpectedContent( +// __DIR__ . '/wrong/wrong2.php.inc', +// __DIR__ . '/correct/correct2.php.inc' +// ); +// $this->doTestFileMatchesExpectedContent( +// __DIR__ . '/wrong/wrong3.php.inc', +// __DIR__ . '/correct/correct3.php.inc' +// ); } } diff --git a/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc b/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc index 49cee4c3dd0..efb7478b394 100644 --- a/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc +++ b/tests/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector/correct/correct.php.inc @@ -1,5 +1,7 @@ Date: Tue, 8 Aug 2017 01:15:01 +0200 Subject: [PATCH 16/22] add FormCallbackRector --- composer.json | 3 +- ...jectAnnotationToConstructorNodeVisitor.php | 7 ++- .../Contrib/Nette/FormCallbackRector.php | 56 ++++++++++++++++--- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index 565724bf3ed..ebb61f3948e 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "rector/rector", - "description": "Tool that reconstructs your legacy code to modern codebase.", + "description": "Refactor legacy code to modern frameworks.", "license": "MIT", "authors": [ { "name": "Tomas Votruba", "email": "tomas.vot@gmail.com", "homepage": "https://tomasvotruba.com" }, @@ -11,7 +11,6 @@ "symfony/console": "^3.3", "symfony/dependency-injection": "^3.3", "nikic/php-parser": "4.0.x-dev as 3.0.2", - "ocramius/code-generator-utils": "^0.4", "nette/utils": "^2.4" }, "require-dev": { diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php index ae5d4d5d353..996fd4bc59e 100644 --- a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php @@ -50,14 +50,13 @@ final class InjectAnnotationToConstructorNodeVisitor extends NodeVisitorAbstract public function enterNode(Node $node) { if ($node instanceof Class_) { - $this->reconstruct($node); - return $node; + return $this->reconstruct($node); } return null; } - private function reconstruct(Class_ $classNode): void + private function reconstruct(Class_ $classNode): Node { foreach ($classNode->stmts as $classElementStatement) { if (! $classElementStatement instanceof Property) { @@ -81,6 +80,8 @@ final class InjectAnnotationToConstructorNodeVisitor extends NodeVisitorAbstract $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); } + + return $classNode; } private function createDocBlockFromProperty(Property $propertyNode): DocBlock diff --git a/src/Rector/Contrib/Nette/FormCallbackRector.php b/src/Rector/Contrib/Nette/FormCallbackRector.php index 5a843afce0f..59caddee382 100644 --- a/src/Rector/Contrib/Nette/FormCallbackRector.php +++ b/src/Rector/Contrib/Nette/FormCallbackRector.php @@ -3,6 +3,11 @@ namespace Rector\Rector\Contrib\Nette; use PhpParser\Node; +use PhpParser\Node\Expr\Array_; +use PhpParser\Node\Expr\ArrayItem; +use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Scalar\String_; +use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; use Rector\Contract\Deprecation\DeprecationInterface; use Rector\Deprecation\SetNames; @@ -12,6 +17,11 @@ use Rector\Deprecation\SetNames; */ final class FormCallbackRector extends NodeVisitorAbstract implements DeprecationInterface { + /** + * @var Node + */ + private $previousNode; + public function getSetName(): string { return SetNames::NETTE; @@ -22,22 +32,52 @@ final class FormCallbackRector extends NodeVisitorAbstract implements Deprecatio return 2.4; } - public function enterNode(Node $node): ?int + /** + * @return int|null|Node + */ + public function enterNode(Node $node) { - if ($this->isCandidate($node)) { - return false; - dump($node); // get next node! - die; + if ($this->previousNode && $this->isFormEventAssign($this->previousNode)) { + if (! $node instanceof PropertyFetch) { + return null; + } - $this->refactor($node); + return new Array_([ + new ArrayItem($node->var), + new ArrayItem( + new String_( + (string) $node->name + ) + ) + ], [ + 'kind' => Array_::KIND_SHORT + ]); + } + + $this->previousNode = $node; + if ($this->isFormEventAssign($node)) { + // do not check children, just go to next token return NodeTraverser::DONT_TRAVERSE_CHILDREN; } return null; } - private function isCandidate(Node $node): bool + private function isFormEventAssign(Node $node): bool { - return $node instanceof Node\Expr\PropertyFetch; + if (! $node instanceof PropertyFetch) { + return false; + } + + if ($node->var->name !== 'form') { + return false; + } + + $propertyName = (string) $node->name; + if (! in_array($propertyName, ['onSuccess', 'onSubmit'], true)) { + return false; + } + + return true; } } From 4d931010d0b6beaa88c5f9cbec81ae4ce81025e0 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Tue, 8 Aug 2017 01:18:55 +0200 Subject: [PATCH 17/22] fix cs --- src/Rector/AbstractRector.php | 2 +- .../Contrib/Nette/FormCallbackRector.php | 27 +++++++++++-------- .../RemoveConfiguratorConstantsRector.php | 2 +- src/Testing/Application/FileReconstructor.php | 10 +------ .../NetteObjectToSmartTraitRector/Test.php | 2 +- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index 48ca7a5870e..920ab3a0582 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -11,7 +11,7 @@ use Rector\Contract\Rector\RectorInterface; abstract class AbstractRector extends NodeVisitorAbstract implements DeprecationInterface, RectorInterface { /** - * @return int|null|Node + * @return null|int|Node */ public function enterNode(Node $node) { diff --git a/src/Rector/Contrib/Nette/FormCallbackRector.php b/src/Rector/Contrib/Nette/FormCallbackRector.php index 59caddee382..f530b9912ca 100644 --- a/src/Rector/Contrib/Nette/FormCallbackRector.php +++ b/src/Rector/Contrib/Nette/FormCallbackRector.php @@ -33,7 +33,7 @@ final class FormCallbackRector extends NodeVisitorAbstract implements Deprecatio } /** - * @return int|null|Node + * @return null|int|Node */ public function enterNode(Node $node) { @@ -42,16 +42,7 @@ final class FormCallbackRector extends NodeVisitorAbstract implements Deprecatio return null; } - return new Array_([ - new ArrayItem($node->var), - new ArrayItem( - new String_( - (string) $node->name - ) - ) - ], [ - 'kind' => Array_::KIND_SHORT - ]); + return $this->createShortArray($node); } $this->previousNode = $node; @@ -80,4 +71,18 @@ final class FormCallbackRector extends NodeVisitorAbstract implements Deprecatio return true; } + + private function createShortArray(Node $node): Array_ + { + return new Array_([ + new ArrayItem($node->var), + new ArrayItem( + new String_( + (string) $node->name + ) + ) + ], [ + 'kind' => Array_::KIND_SHORT + ]); + } } diff --git a/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php b/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php index a2c2eb26bde..801bd4e38f9 100644 --- a/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php +++ b/src/Rector/Contrib/Nette/RemoveConfiguratorConstantsRector.php @@ -4,9 +4,9 @@ namespace Rector\Rector\Contrib\Nette; use PhpParser\Node; use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Scalar\String_; use Rector\Deprecation\SetNames; use Rector\Rector\AbstractRector; -use PhpParser\Node\Scalar\String_; final class RemoveConfiguratorConstantsRector extends AbstractRector { diff --git a/src/Testing/Application/FileReconstructor.php b/src/Testing/Application/FileReconstructor.php index 92e1ad699d5..c4597646564 100644 --- a/src/Testing/Application/FileReconstructor.php +++ b/src/Testing/Application/FileReconstructor.php @@ -5,7 +5,6 @@ namespace Rector\Testing\Application; use PhpParser\Lexer; use PhpParser\NodeTraverser; use PhpParser\Parser; -use Rector\NodeTraverser\StateHolder; use Rector\Printer\FormatPerservingPrinter; use SplFileInfo; @@ -31,23 +30,16 @@ final class FileReconstructor */ private $nodeTraverser; - /** - * @var StateHolder - */ - private $stateHolder; - public function __construct( Parser $parser, FormatPerservingPrinter $codeStyledPrinter, Lexer $lexer, - NodeTraverser $nodeTraverser, - StateHolder $stateHolder + NodeTraverser $nodeTraverser ) { $this->parser = $parser; $this->codeStyledPrinter = $codeStyledPrinter; $this->lexer = $lexer; $this->nodeTraverser = $nodeTraverser; - $this->stateHolder = $stateHolder; } // ref: https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516 diff --git a/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php index 5106cc5f85d..3f9cb5e3e3b 100644 --- a/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php +++ b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php @@ -12,7 +12,7 @@ final class Test extends AbstractReconstructorTestCase __DIR__ . '/wrong/wrong.php.inc', __DIR__ . '/correct/correct.php.inc' ); -// $this->doTestFileMatchesExpectedContent( + // $this->doTestFileMatchesExpectedContent( // __DIR__ . '/wrong/wrong2.php.inc', // __DIR__ . '/correct/correct2.php.inc' // ); From d8849f04cd2b4e199739b82d0c5e91eda851306f Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Tue, 8 Aug 2017 01:20:16 +0200 Subject: [PATCH 18/22] add uncommented tests --- .../Nette/NetteObjectToSmartTraitRector/Test.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php index 3f9cb5e3e3b..ea2b3c430b9 100644 --- a/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php +++ b/tests/Rector/Contrib/Nette/NetteObjectToSmartTraitRector/Test.php @@ -12,13 +12,13 @@ final class Test extends AbstractReconstructorTestCase __DIR__ . '/wrong/wrong.php.inc', __DIR__ . '/correct/correct.php.inc' ); - // $this->doTestFileMatchesExpectedContent( -// __DIR__ . '/wrong/wrong2.php.inc', -// __DIR__ . '/correct/correct2.php.inc' -// ); -// $this->doTestFileMatchesExpectedContent( -// __DIR__ . '/wrong/wrong3.php.inc', -// __DIR__ . '/correct/correct3.php.inc' -// ); + $this->doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong2.php.inc', + __DIR__ . '/correct/correct2.php.inc' + ); + $this->doTestFileMatchesExpectedContent( + __DIR__ . '/wrong/wrong3.php.inc', + __DIR__ . '/correct/correct3.php.inc' + ); } } From 7d5a1250eb616e398ed1a7f4905aea097e4bfab4 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Tue, 8 Aug 2017 01:59:37 +0200 Subject: [PATCH 19/22] rename StateHolder, to TokenSwitcher --- src/NodeTraverser/StateHolder.php | 21 --- src/NodeTraverser/TokenSwitcher.php | 21 +++ ...jectAnnotationToConstructorNodeVisitor.php | 107 --------------- .../InjectAnnotationToConstructorRector.php | 127 ++++++++++++++++++ .../AddPropertiesToClassNodeVisitor.php | 12 +- .../Nette/NetteObjectToSmartTraitRector.php | 16 ++- src/Testing/Application/FileReconstructor.php | 14 +- .../Test.php | 2 +- .../correct/correct.php.inc | 2 + .../wrong/wrong.php.inc | 0 10 files changed, 182 insertions(+), 140 deletions(-) delete mode 100644 src/NodeTraverser/StateHolder.php create mode 100644 src/NodeTraverser/TokenSwitcher.php delete mode 100644 src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php create mode 100644 src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php rename tests/NodeVisitor/DependencyInjection/{InjectAnnotationToConstructorReconstructor => InjectAnnotationToConstructorRector}/Test.php (92%) rename tests/NodeVisitor/DependencyInjection/{InjectAnnotationToConstructorReconstructor => InjectAnnotationToConstructorRector}/correct/correct.php.inc (99%) rename tests/NodeVisitor/DependencyInjection/{InjectAnnotationToConstructorReconstructor => InjectAnnotationToConstructorRector}/wrong/wrong.php.inc (100%) diff --git a/src/NodeTraverser/StateHolder.php b/src/NodeTraverser/StateHolder.php deleted file mode 100644 index 941bf55845e..00000000000 --- a/src/NodeTraverser/StateHolder.php +++ /dev/null @@ -1,21 +0,0 @@ -isAfterTraverseCalled = true; - } - - public function isAfterTraverseCalled(): bool - { - return $this->isAfterTraverseCalled; - } -} diff --git a/src/NodeTraverser/TokenSwitcher.php b/src/NodeTraverser/TokenSwitcher.php new file mode 100644 index 00000000000..ecaa4395d10 --- /dev/null +++ b/src/NodeTraverser/TokenSwitcher.php @@ -0,0 +1,21 @@ +isEnabled = true; + } + + public function isEnabled(): bool + { + return $this->isEnabled; + } +} diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php deleted file mode 100644 index 996fd4bc59e..00000000000 --- a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php +++ /dev/null @@ -1,107 +0,0 @@ -constructorMethodBuilder = $constructorMethodBuilder; - } - - public function isCandidate(Node $node): bool - { - return $node instanceof Class_; - } - - /** - * Called when entering a node. - * - * Return value semantics: - * * null - * => $node stays as-is - * * NodeTraverser::DONT_TRAVERSE_CHILDREN - * => Children of $node are not traversed. $node stays as-is - * * NodeTraverser::STOP_TRAVERSAL - * => Traversal is aborted. $node stays as-is - * * otherwise - * => $node is set to the return value - * - * @return null|int|Node Replacement node (or special return value) - */ - public function enterNode(Node $node) - { - if ($node instanceof Class_) { - return $this->reconstruct($node); - } - - return null; - } - - private function reconstruct(Class_ $classNode): Node - { - foreach ($classNode->stmts as $classElementStatement) { - if (! $classElementStatement instanceof Property) { - continue; - } - - $propertyNode = $classElementStatement; - - $propertyDocBlock = $this->createDocBlockFromProperty($propertyNode); - $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); - if (! $injectAnnotations) { - continue; - } - - $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); - $this->makePropertyPrivate($propertyNode); - - $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0] - ->getTypes()[0]; - $propertyName = (string) $propertyNode->props[0]->name; - - $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); - } - - return $classNode; - } - - private function createDocBlockFromProperty(Property $propertyNode): DocBlock - { - return new DocBlock($propertyNode->getDocComment()); - } - - private function makePropertyPrivate(Property $propertyNode): void - { - $propertyNode->flags = Class_::MODIFIER_PRIVATE; - } - - private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): void - { - $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); - - foreach ($injectAnnotations as $injectAnnotation) { - $injectAnnotation->remove(); - } - - $propertyNode->setDocComment(new Doc($propertyDocBlock->getContent())); - } -} diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php new file mode 100644 index 00000000000..567c0113f63 --- /dev/null +++ b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php @@ -0,0 +1,127 @@ +constructorMethodBuilder = $constructorMethodBuilder; +// } + + public function __construct(TokenSwitcher $tokenSwitcher) + { + $this->tokenSwitcher = $tokenSwitcher; + } + + public function enterNode(Node $node): ?Node + { + if (! $this->isCandidate($node)) { + return null; + } + + return $this->reconstructProperty($node); + } + + public function isCandidate(Node $node): bool + { + if (! $node instanceof Property) { + return false; + } + + if (! $this->hasInjectAnnotation($node)) { + return false; + } + + $this->tokenSwitcher->enable(); + return true; + } + +// private function reconstruct(Class_ $classNode): Node +// { +// dump($classNode); +// die; +// +// foreach ($classNode->stmts as $classElementStatement) { +// if (! $classElementStatement instanceof Property) { +// continue; +// } +// +// $propertyNode = $classElementStatement; +// +// $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); +// $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); +// if (! $injectAnnotations) { +// continue; +// } +// +// $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); +// $this->makePropertyPrivate($propertyNode); +// +// $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0] +// ->getTypes()[0]; +// $propertyName = (string) $propertyNode->props[0]->name; +// +// $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); +// } +// +// return $classNode; +// } + + private function reconstructProperty($propertyNode): Property + { + $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); + $propertyNode = $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); + +// $propertyNode->flags = Class_::MODIFIER_PRIVATE; + + return $propertyNode; + } + + private function hasInjectAnnotation(Property $propertyNode): bool + { + $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); + + return (bool) $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); + } + + private function createDocBlockFromNode(Node $node): DocBlock + { + return new DocBlock($node->getDocComment()); + } + + private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): Property + { + $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); + + foreach ($injectAnnotations as $injectAnnotation) { + $injectAnnotation->remove(); + } + + $propertyNode->setDocComment(new Doc($propertyDocBlock->getContent())); + + return $propertyNode; + } +} diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php index 0b9fbfd2b99..857f8630dea 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php @@ -8,7 +8,7 @@ use PhpParser\NodeVisitorAbstract; use Rector\Builder\Class_\ClassPropertyCollector; use Rector\Builder\ConstructorMethodBuilder; use Rector\Builder\PropertyBuilder; -use Rector\NodeTraverser\StateHolder; +use Rector\NodeTraverser\TokenSwitcher; /** * Add new propertis to class and to contructor. @@ -31,20 +31,20 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract private $newClassPropertyCollector; /** - * @var StateHolder + * @var TokenSwitcher */ - private $stateHolder; + private $tokenSwitcher; public function __construct( ConstructorMethodBuilder $constructorMethodBuilder, PropertyBuilder $propertyBuilder, ClassPropertyCollector $newClassPropertyCollector, - StateHolder $stateHolder + TokenSwitcher $tokenSwitcher ) { $this->constructorMethodBuilder = $constructorMethodBuilder; $this->propertyBuilder = $propertyBuilder; $this->newClassPropertyCollector = $newClassPropertyCollector; - $this->stateHolder = $stateHolder; + $this->tokenSwitcher = $tokenSwitcher; } /** @@ -68,7 +68,7 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract $propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($className); foreach ($propertiesForClass as $propertyType => $propertyName) { - $this->stateHolder->setAfterTraverserIsCalled(); + $this->tokenSwitcher->enable(); $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); $this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName); } diff --git a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php index 3d9f6452b55..0810daee324 100644 --- a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php +++ b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php @@ -8,6 +8,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\TraitUse; use Rector\Builder\StatementGlue; use Rector\Deprecation\SetNames; +use Rector\NodeTraverser\TokenSwitcher; use Rector\Rector\AbstractRector; /** @@ -20,9 +21,15 @@ final class NetteObjectToSmartTraitRector extends AbstractRector */ private $statementGlue; - public function __construct(StatementGlue $statementGlue) + /** + * @var TokenSwitcher + */ + private $tokenSwitcher; + + public function __construct(StatementGlue $statementGlue, TokenSwitcher $tokenSwitcher) { $this->statementGlue = $statementGlue; + $this->tokenSwitcher = $tokenSwitcher; } public function getSetName(): string @@ -47,6 +54,7 @@ final class NetteObjectToSmartTraitRector extends AbstractRector return false; } + $this->tokenSwitcher->enable(); return true; } @@ -58,12 +66,12 @@ final class NetteObjectToSmartTraitRector extends AbstractRector */ public function refactor($classNode): ?Node { - // remove parent class - $classNode->extends = null; - $traitUseNode = $this->createTraitUse('Nette\SmartObject'); $this->statementGlue->addAsFirstTrait($classNode, $traitUseNode); + // remove parent class + $classNode->extends = null; + return $classNode; } diff --git a/src/Testing/Application/FileReconstructor.php b/src/Testing/Application/FileReconstructor.php index c4597646564..67e4ac22fd3 100644 --- a/src/Testing/Application/FileReconstructor.php +++ b/src/Testing/Application/FileReconstructor.php @@ -5,6 +5,7 @@ namespace Rector\Testing\Application; use PhpParser\Lexer; use PhpParser\NodeTraverser; use PhpParser\Parser; +use Rector\NodeTraverser\TokenSwitcher; use Rector\Printer\FormatPerservingPrinter; use SplFileInfo; @@ -30,16 +31,23 @@ final class FileReconstructor */ private $nodeTraverser; + /** + * @var TokenSwitcher + */ + private $tokenSwitcher; + public function __construct( Parser $parser, FormatPerservingPrinter $codeStyledPrinter, Lexer $lexer, - NodeTraverser $nodeTraverser + NodeTraverser $nodeTraverser, + TokenSwitcher $tokenSwitcher ) { $this->parser = $parser; $this->codeStyledPrinter = $codeStyledPrinter; $this->lexer = $lexer; $this->nodeTraverser = $nodeTraverser; + $this->tokenSwitcher = $tokenSwitcher; } // ref: https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516 @@ -51,6 +59,10 @@ final class FileReconstructor $oldTokens = $this->lexer->getTokens(); $newStmts = $this->nodeTraverser->traverse($oldStmts); + if ($this->tokenSwitcher->isEnabled()) { + [$oldStmts, $newStmts] = [$newStmts, $oldStmts]; + } + return $this->codeStyledPrinter->printToString($newStmts, $oldStmts, $oldTokens); } } diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/Test.php b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/Test.php similarity index 92% rename from tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/Test.php rename to tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/Test.php index 76095660d82..7d7f2a93ab6 100644 --- a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/Test.php +++ b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/Test.php @@ -1,6 +1,6 @@ property = $property; diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/wrong/wrong.php.inc b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/wrong/wrong.php.inc similarity index 100% rename from tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/wrong/wrong.php.inc rename to tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/wrong/wrong.php.inc From 70bb18f099b14ace88be2d9878a5b3bd314ba9e6 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Tue, 8 Aug 2017 02:30:29 +0200 Subject: [PATCH 20/22] renaming --- src/Builder/Class_/ClassPropertyCollector.php | 4 +- .../AddPropertiesToClassNodeVisitor.php | 22 ++--- .../PropertyRector.php} | 91 ++++++++++--------- ...Visitor.php => GetterToPropertyRector.php} | 23 +---- .../correct/correct.php.inc | 1 - .../Source/LocalKernel.php | 2 +- .../Source/services.yml | 0 .../Test.php | 2 +- .../correct/correct.php.inc | 0 .../correct/correct2.php.inc | 0 .../correct/correct3.php.inc | 0 .../wrong/wrong.php.inc | 0 .../wrong/wrong2.php.inc | 0 .../wrong/wrong3.php.inc | 0 14 files changed, 60 insertions(+), 85 deletions(-) rename src/NodeVisitor/DependencyInjection/{NamedServicesToConstructor => }/AddPropertiesToClassNodeVisitor.php (76%) rename src/NodeVisitor/DependencyInjection/{InjectAnnotationToConstructorRector.php => InjectAnnotationToConstructor/PropertyRector.php} (55%) rename src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/{GetterToPropertyNodeVisitor.php => GetterToPropertyRector.php} (88%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/Source/LocalKernel.php (95%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/Source/services.yml (100%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/Test.php (95%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/correct/correct.php.inc (100%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/correct/correct2.php.inc (100%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/correct/correct3.php.inc (100%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/wrong/wrong.php.inc (100%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/wrong/wrong2.php.inc (100%) rename tests/NodeVisitor/DependencyInjection/{NamedServicesToConstructorReconstructor => NamedServicesToConstructorRector}/wrong/wrong3.php.inc (100%) diff --git a/src/Builder/Class_/ClassPropertyCollector.php b/src/Builder/Class_/ClassPropertyCollector.php index 13f4bb9ee2e..038ba46c067 100644 --- a/src/Builder/Class_/ClassPropertyCollector.php +++ b/src/Builder/Class_/ClassPropertyCollector.php @@ -11,9 +11,7 @@ final class ClassPropertyCollector public function addPropertyForClass(string $class, string $propertyType, string $propertyName): void { - $this->classProperties[$class] = [ - $propertyType => $propertyName, - ]; + $this->classProperties[$class][$propertyType] = $propertyName; } /** diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php b/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php similarity index 76% rename from src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php rename to src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php index 857f8630dea..dbc9f534c88 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php @@ -1,6 +1,6 @@ constructorMethodBuilder = $constructorMethodBuilder; $this->propertyBuilder = $propertyBuilder; $this->newClassPropertyCollector = $newClassPropertyCollector; - $this->tokenSwitcher = $tokenSwitcher; } /** @@ -53,24 +45,24 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract */ public function afterTraverse(array $nodes): array { - foreach ($nodes as $node) { + foreach ($nodes as $key => $node) { if ($node instanceof Class_) { - $this->reconstruct($node, (string) $node->name); - break; + $nodes[$key] = $this->reconstruct($node, (string) $node->name); } } return $nodes; } - private function reconstruct(Class_ $classNode, string $className): void + private function reconstruct(Class_ $classNode, string $className): Class_ { $propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($className); foreach ($propertiesForClass as $propertyType => $propertyName) { - $this->tokenSwitcher->enable(); $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); $this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName); } + + return $classNode; } } diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php similarity index 55% rename from src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php rename to src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php index 567c0113f63..c06c4f3eb2a 100644 --- a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php +++ b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php @@ -1,15 +1,17 @@ constructorMethodBuilder = $constructorMethodBuilder; -// } + /** + * @var ClassPropertyCollector + */ + private $classPropertyCollector; - public function __construct(TokenSwitcher $tokenSwitcher) + /** + * @var string + */ + private $className; + + public function __construct(TokenSwitcher $tokenSwitcher, ClassPropertyCollector $classPropertyCollector) { $this->tokenSwitcher = $tokenSwitcher; + $this->classPropertyCollector = $classPropertyCollector; + } + + /** + * @param Node[] $nodes + * @return null|array + */ + public function beforeTraverse(array $nodes): ?array + { + dump('1'); + foreach ($nodes as $node) { + if ($node instanceof Class_) { + $this->className = (string) $node->name; + } + } + + return null; } public function enterNode(Node $node): ?Node @@ -42,6 +61,8 @@ final class InjectAnnotationToConstructorRector extends NodeVisitorAbstract return null; } + dump('2'); + return $this->reconstructProperty($node); } @@ -59,43 +80,14 @@ final class InjectAnnotationToConstructorRector extends NodeVisitorAbstract return true; } -// private function reconstruct(Class_ $classNode): Node -// { -// dump($classNode); -// die; -// -// foreach ($classNode->stmts as $classElementStatement) { -// if (! $classElementStatement instanceof Property) { -// continue; -// } -// -// $propertyNode = $classElementStatement; -// -// $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); -// $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); -// if (! $injectAnnotations) { -// continue; -// } -// -// $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); -// $this->makePropertyPrivate($propertyNode); -// -// $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0] -// ->getTypes()[0]; -// $propertyName = (string) $propertyNode->props[0]->name; -// -// $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); -// } -// -// return $classNode; -// } - private function reconstructProperty($propertyNode): Property { $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); $propertyNode = $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); -// $propertyNode->flags = Class_::MODIFIER_PRIVATE; + $propertyNode->flags = Class_::MODIFIER_PRIVATE; + + $this->addPropertyToCollector($propertyNode, $propertyDocBlock); return $propertyNode; } @@ -115,7 +107,6 @@ final class InjectAnnotationToConstructorRector extends NodeVisitorAbstract private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): Property { $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); - foreach ($injectAnnotations as $injectAnnotation) { $injectAnnotation->remove(); } @@ -124,4 +115,14 @@ final class InjectAnnotationToConstructorRector extends NodeVisitorAbstract return $propertyNode; } + + private function addPropertyToCollector(Property $propertyNode, DocBlock $propertyDocBlock): void + { + $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0] + ->getTypes()[0]; + + $propertyName = (string)$propertyNode->props[0]->name; + + $this->classPropertyCollector->addPropertyForClass($this->className, $propertyType, $propertyName); + } } diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php similarity index 88% rename from src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php rename to src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php index 18384bd4c7f..45e323be49e 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php @@ -13,7 +13,7 @@ use PhpParser\NodeVisitorAbstract; use Rector\Builder\Class_\ClassPropertyCollector; use Rector\Builder\Kernel\ServiceFromKernelResolver; use Rector\Builder\Naming\NameResolver; -use Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor\Source\LocalKernel; +use Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorRector\Source\LocalKernel; /** * Converts all: @@ -22,7 +22,7 @@ use Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorRecon * into: * $this->someService # where "someService" is type of the service */ -final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract +final class GetterToPropertyRector extends NodeVisitorAbstract { /** * @var string @@ -69,25 +69,10 @@ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract return null; } - /** - * Return value semantics: - * * null - * => $node stays as-is - * * NodeTraverser::DONT_TRAVERSE_CHILDREN - * => Children of $node are not traversed. $node stays as-is - * * NodeTraverser::STOP_TRAVERSAL - * => Traversal is aborted. $node stays as-is - * * otherwise - * => $node is set to the return value. - * - * @return null|int|Node - */ - public function enterNode(Node $node) + public function enterNode(Node $node): ?Node { if ($this->isCandidate($node)) { - $this->reconstruct($node); - - return $node; + return $this->reconstruct($node); } return null; diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc index 57ec4a63833..5154e980d9f 100644 --- a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc +++ b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc @@ -6,7 +6,6 @@ class ClassWithInjects * @var stdClass */ private $property; - /** * @var DateTimeInterface */ diff --git a/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Source/LocalKernel.php b/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorRector/Source/LocalKernel.php similarity index 95% rename from tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Source/LocalKernel.php rename to tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorRector/Source/LocalKernel.php index 0f812a061c8..bc404e115f2 100644 --- a/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Source/LocalKernel.php +++ b/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorRector/Source/LocalKernel.php @@ -1,6 +1,6 @@ Date: Tue, 8 Aug 2017 17:55:38 +0200 Subject: [PATCH 21/22] add NodeTraverserFactory --- .../CompilerPass/CollectorCompilerPass.php | 6 ++-- src/NodeTraverser/NodeTraverserFactory.php | 34 +++++++++++++++++++ src/NodeTraverser/TokenSwitcher.php | 5 +++ .../AddPropertiesToClassNodeVisitor.php | 16 ++++++++- .../PropertyRector.php | 3 -- src/config/services.yml | 5 +-- .../correct/correct.php.inc | 1 + 7 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 src/NodeTraverser/NodeTraverserFactory.php diff --git a/src/DependencyInjection/CompilerPass/CollectorCompilerPass.php b/src/DependencyInjection/CompilerPass/CollectorCompilerPass.php index 889e2d4d734..04d7f89de5e 100644 --- a/src/DependencyInjection/CompilerPass/CollectorCompilerPass.php +++ b/src/DependencyInjection/CompilerPass/CollectorCompilerPass.php @@ -2,8 +2,8 @@ namespace Rector\DependencyInjection\CompilerPass; -use PhpParser\NodeTraverser; use PhpParser\NodeVisitor; +use Rector\NodeTraverser\NodeTraverserFactory; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; @@ -32,9 +32,9 @@ final class CollectorCompilerPass implements CompilerPassInterface { DefinitionCollector::loadCollectorWithType( $containerBuilder, - NodeTraverser::class, + NodeTraverserFactory::class, NodeVisitor::class, - 'addVisitor' + 'addNodeVisitor' ); } } diff --git a/src/NodeTraverser/NodeTraverserFactory.php b/src/NodeTraverser/NodeTraverserFactory.php new file mode 100644 index 00000000000..fcd2a082cf9 --- /dev/null +++ b/src/NodeTraverser/NodeTraverserFactory.php @@ -0,0 +1,34 @@ +nodeVisitors[] = $nodeVisitor; + } + + public function create(): NodeTraverser + { + $nodeTraverser = new NodeTraverser; + + // this one has priority + $nodeTraverser->addVisitor(new CloningVisitor); + + foreach ($this->nodeVisitors as $nodeVisitor) { + $nodeTraverser->addVisitor($nodeVisitor); + } + + return $nodeTraverser; + } +} diff --git a/src/NodeTraverser/TokenSwitcher.php b/src/NodeTraverser/TokenSwitcher.php index ecaa4395d10..a469125ed64 100644 --- a/src/NodeTraverser/TokenSwitcher.php +++ b/src/NodeTraverser/TokenSwitcher.php @@ -14,6 +14,11 @@ final class TokenSwitcher $this->isEnabled = true; } + public function disable(): void + { + $this->isEnabled = false; + } + public function isEnabled(): bool { return $this->isEnabled; diff --git a/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php b/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php index dbc9f534c88..c52b38091c1 100644 --- a/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php @@ -8,6 +8,7 @@ use PhpParser\NodeVisitorAbstract; use Rector\Builder\Class_\ClassPropertyCollector; use Rector\Builder\ConstructorMethodBuilder; use Rector\Builder\PropertyBuilder; +use Rector\NodeTraverser\TokenSwitcher; /** * Add new propertis to class and to contructor. @@ -29,14 +30,21 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract */ private $newClassPropertyCollector; + /** + * @var TokenSwitcher + */ + private $tokenSwitcher; + public function __construct( ConstructorMethodBuilder $constructorMethodBuilder, PropertyBuilder $propertyBuilder, - ClassPropertyCollector $newClassPropertyCollector + ClassPropertyCollector $newClassPropertyCollector, + TokenSwitcher $tokenSwitcher ) { $this->constructorMethodBuilder = $constructorMethodBuilder; $this->propertyBuilder = $propertyBuilder; $this->newClassPropertyCollector = $newClassPropertyCollector; + $this->tokenSwitcher = $tokenSwitcher; } /** @@ -48,9 +56,13 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract foreach ($nodes as $key => $node) { if ($node instanceof Class_) { $nodes[$key] = $this->reconstruct($node, (string) $node->name); + break; } } + // this does! + $this->tokenSwitcher->disable(); + return $nodes; } @@ -58,6 +70,8 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract { $propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($className); + dump($propertiesForClass); + foreach ($propertiesForClass as $propertyType => $propertyName) { $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); $this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName); diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php index c06c4f3eb2a..a8b6ed60b59 100644 --- a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php +++ b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php @@ -45,7 +45,6 @@ final class PropertyRector extends NodeVisitorAbstract */ public function beforeTraverse(array $nodes): ?array { - dump('1'); foreach ($nodes as $node) { if ($node instanceof Class_) { $this->className = (string) $node->name; @@ -61,8 +60,6 @@ final class PropertyRector extends NodeVisitorAbstract return null; } - dump('2'); - return $this->reconstructProperty($node); } diff --git a/src/config/services.yml b/src/config/services.yml index 9a8a0e4bbc6..d5d419ec9fc 100644 --- a/src/config/services.yml +++ b/src/config/services.yml @@ -20,9 +20,10 @@ services: factory: ['@Rector\Parser\LexerFactory', 'create'] PhpParser\BuilderFactory: ~ + PhpParser\NodeTraverser: + factory: ['@Rector\NodeTraverser\NodeTraverserFactory', 'create'] + # Traverser - PhpParser\NodeTraverser: ~ PhpParser\ParserFactory: ~ # Printer - PhpParser\NodeVisitor\CloningVisitor: ~ PhpParser\PrettyPrinter\Standard: ~ diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc index 5154e980d9f..57ec4a63833 100644 --- a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc +++ b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc @@ -6,6 +6,7 @@ class ClassWithInjects * @var stdClass */ private $property; + /** * @var DateTimeInterface */ From 478ce6413824e547bc8d97f0774134f0be82a892 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Tue, 8 Aug 2017 18:17:40 +0200 Subject: [PATCH 22/22] fix it all --- easy-coding-standard.neon | 1 + src/Builder/PropertyBuilder.php | 20 +++++++++ src/NodeTraverser/NodeTraverserFactory.php | 20 ++++++++- .../AddPropertiesToClassNodeVisitor.php | 2 - .../PropertyRector.php | 2 + .../GetterToPropertyRector.php | 2 + .../Traverse/NodeConnectorNodeVisitor.php | 45 +++++++++++++++++++ .../Traverse/ParentConnectorNodeVisitor.php | 33 ++++++++++++++ src/Printer/FormatPerservingPrinter.php | 1 - .../correct/correct.php.inc | 2 - 10 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 src/NodeVisitor/Traverse/NodeConnectorNodeVisitor.php create mode 100644 src/NodeVisitor/Traverse/ParentConnectorNodeVisitor.php diff --git a/easy-coding-standard.neon b/easy-coding-standard.neon index e7be08bf21c..b2daddc770e 100644 --- a/easy-coding-standard.neon +++ b/easy-coding-standard.neon @@ -41,6 +41,7 @@ checkers: # Namespaces - PhpCsFixer\Fixer\Import\OrderedImportsFixer + - PhpCsFixer\Fixer\Import\NoUnusedImportsFixer PhpCsFixer\Fixer\Operator\ConcatSpaceFixer: spacing: one diff --git a/src/Builder/PropertyBuilder.php b/src/Builder/PropertyBuilder.php index a0237e9b53a..68eeb6d13b2 100644 --- a/src/Builder/PropertyBuilder.php +++ b/src/Builder/PropertyBuilder.php @@ -27,6 +27,10 @@ final class PropertyBuilder public function addPropertyToClass(Class_ $classNode, string $propertyType, string $propertyName): void { + if ($this->doesPropertyAlreadyExist($classNode, $propertyName)) { + return; + } + $propertyNode = $this->buildPrivatePropertyNode($propertyType, $propertyName); $this->statementGlue->addAsFirstMethod($classNode, $propertyNode); @@ -49,4 +53,20 @@ final class PropertyBuilder . PHP_EOL . ' * @var ' . $propertyType . PHP_EOL . ' */'); } + + private function doesPropertyAlreadyExist(Class_ $classNode, string $propertyName): bool + { + foreach ($classNode->stmts as $inClassNode) { + if (! $inClassNode instanceof Property) { + continue; + } + + $classPropertyName = (string) $inClassNode->props[0]->name; + if ($classPropertyName === $propertyName) { + return true; + } + } + + return false; + } } diff --git a/src/NodeTraverser/NodeTraverserFactory.php b/src/NodeTraverser/NodeTraverserFactory.php index fcd2a082cf9..9ae2e29e10c 100644 --- a/src/NodeTraverser/NodeTraverserFactory.php +++ b/src/NodeTraverser/NodeTraverserFactory.php @@ -5,6 +5,8 @@ namespace Rector\NodeTraverser; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor; use PhpParser\NodeVisitor\CloningVisitor; +use Rector\NodeVisitor\Traverse\NodeConnectorNodeVisitor; +use Rector\NodeVisitor\Traverse\ParentConnectorNodeVisitor; final class NodeTraverserFactory { @@ -13,6 +15,15 @@ final class NodeTraverserFactory */ private $nodeVisitors = []; + /** + * @var string[] + */ + private $priorityNodeVisitorClasses = [ + CloningVisitor::class, + ParentConnectorNodeVisitor::class, + NodeConnectorNodeVisitor::class + ]; + public function addNodeVisitor(NodeVisitor $nodeVisitor): void { $this->nodeVisitors[] = $nodeVisitor; @@ -22,10 +33,15 @@ final class NodeTraverserFactory { $nodeTraverser = new NodeTraverser; - // this one has priority - $nodeTraverser->addVisitor(new CloningVisitor); + foreach ($this->priorityNodeVisitorClasses as $priorityNodeVisitor) { + $nodeTraverser->addVisitor(new $priorityNodeVisitor); + } foreach ($this->nodeVisitors as $nodeVisitor) { + if (in_array(get_class($nodeVisitor), $this->priorityNodeVisitorClasses, true)) { + continue; + } + $nodeTraverser->addVisitor($nodeVisitor); } diff --git a/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php b/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php index c52b38091c1..1dd89f29c92 100644 --- a/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/AddPropertiesToClassNodeVisitor.php @@ -70,8 +70,6 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract { $propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($className); - dump($propertiesForClass); - foreach ($propertiesForClass as $propertyType => $propertyName) { $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); $this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName); diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php index a8b6ed60b59..0d4e9bde0cd 100644 --- a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php +++ b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructor/PropertyRector.php @@ -45,6 +45,8 @@ final class PropertyRector extends NodeVisitorAbstract */ public function beforeTraverse(array $nodes): ?array { + $this->className = null; + foreach ($nodes as $node) { if ($node instanceof Class_) { $this->className = (string) $node->name; diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php index 45e323be49e..2ede1dc2689 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyRector.php @@ -60,6 +60,8 @@ final class GetterToPropertyRector extends NodeVisitorAbstract */ public function beforeTraverse(array $nodes): ?array { + $this->className = null; + foreach ($nodes as $node) { if ($node instanceof Class_) { $this->className = (string) $node->name; diff --git a/src/NodeVisitor/Traverse/NodeConnectorNodeVisitor.php b/src/NodeVisitor/Traverse/NodeConnectorNodeVisitor.php new file mode 100644 index 00000000000..ce9b30d935e --- /dev/null +++ b/src/NodeVisitor/Traverse/NodeConnectorNodeVisitor.php @@ -0,0 +1,45 @@ +stack = []; + $this->prev = null; + } + + public function enterNode(Node $node): void + { + if (! empty($this->stack)) { + $node->setAttribute('parent', $this->stack[count($this->stack)-1]); + } + + if ($this->prev && $this->prev->getAttribute('parent') === $node->getAttribute('parent')) { + $node->setAttribute('prev', $this->prev); + $this->prev->setAttribute('next', $node); + } + + $this->stack[] = $node; + } + + public function leaveNode(Node $node): void + { + $this->prev = $node; + array_pop($this->stack); + } +} diff --git a/src/NodeVisitor/Traverse/ParentConnectorNodeVisitor.php b/src/NodeVisitor/Traverse/ParentConnectorNodeVisitor.php new file mode 100644 index 00000000000..e9dbc37750b --- /dev/null +++ b/src/NodeVisitor/Traverse/ParentConnectorNodeVisitor.php @@ -0,0 +1,33 @@ +stack = []; + } + + public function enterNode(Node $node): void + { + if (! empty($this->stack)) { + $node->setAttribute('parent', $this->stack[count($this->stack)-1]); + } + + $this->stack[] = $node; + } + + public function leaveNode(Node $node): void + { + array_pop($this->stack); + } +} diff --git a/src/Printer/FormatPerservingPrinter.php b/src/Printer/FormatPerservingPrinter.php index 8b046b22298..ca6a78676e3 100644 --- a/src/Printer/FormatPerservingPrinter.php +++ b/src/Printer/FormatPerservingPrinter.php @@ -4,7 +4,6 @@ namespace Rector\Printer; use PhpParser\PrettyPrinter\Standard; use SplFileInfo; -use Tracy\Debugger; final class FormatPerservingPrinter { diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc index 57ec4a63833..19ed81e6394 100644 --- a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc +++ b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/correct/correct.php.inc @@ -6,12 +6,10 @@ class ClassWithInjects * @var stdClass */ private $property; - /** * @var DateTimeInterface */ private $otherProperty; - public function __construct(stdClass $property, DateTimeInterface $otherProperty) { $this->property = $property;