From 23fe195c842e3e046a685bc3e2c8bc07eb8bd147 Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Wed, 2 Oct 2019 16:33:58 +0200 Subject: [PATCH 1/6] Trying to implement this feature. Not there yet. --- .../ImportFullyQualifiedNamesRector.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php index a9af31e88016..cf3b7989e6a6 100644 --- a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php +++ b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php @@ -19,15 +19,24 @@ final class ImportFullyQualifiedNamesRector extends AbstractRector */ private $shouldImportDocBlocks = true; + /** + * @var bool + */ + private $shouldImportRootNamespaceClasses = true; + /** * @var NameImporter */ private $nameImporter; - public function __construct(NameImporter $nameImporter, bool $shouldImportDocBlocks = true) - { + public function __construct( + NameImporter $nameImporter, + bool $shouldImportDocBlocks = true, + bool $shouldImportRootNamespaceClasses = true + ) { $this->nameImporter = $nameImporter; $this->shouldImportDocBlocks = $shouldImportDocBlocks; + $this->shouldImportRootNamespaceClasses = $shouldImportRootNamespaceClasses; } public function getDefinition(): RectorDefinition @@ -72,6 +81,11 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { + // Importing root namespace classes (like \DateTime) is optional + if (!$this->shouldImportRootNamespaceClasses && $node instanceof Name && !$node->isQualified()) { + return null; + } + $this->useAddingCommander->analyseFileInfoUseStatements($node); if ($node instanceof Name) { From 4c5b5340ef55fe9236500e2606f97ad1af725294 Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Wed, 2 Oct 2019 17:02:50 +0200 Subject: [PATCH 2/6] Adding a test. --- ...rt_root_namespace_classes_disabled.php.inc | 29 +++++++++ ...ort_root_namespace_classes_enabled.php.inc | 62 +++++++++++++++++++ .../ImportFullyQualifiedNamesRectorTest.php | 2 + ...ImportRootNamespaceClassesDisabledTest.php | 33 ++++++++++ 4 files changed, 126 insertions(+) create mode 100644 packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc create mode 100644 packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_enabled.php.inc create mode 100644 packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php diff --git a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc new file mode 100644 index 000000000000..9e78a31299a7 --- /dev/null +++ b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc @@ -0,0 +1,29 @@ +date = $currentDate; + } + + public function setDate(?\DateTime $date): void + { + $this->date = $date; + } + + public function getDate(): ?\DateTime + { + return $this->date; + } +} diff --git a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_enabled.php.inc b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_enabled.php.inc new file mode 100644 index 000000000000..7c1629c8d0b8 --- /dev/null +++ b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_enabled.php.inc @@ -0,0 +1,62 @@ +date = $currentDate; + } + + public function setDate(?\DateTime $date): void + { + $this->date = $date; + } + + public function getDate(): ?\DateTime + { + return $this->date; + } +} +?> +----- +date = $currentDate; + } + + public function setDate(?DateTime $date): void + { + $this->date = $date; + } + + public function getDate(): ?DateTime + { + return $this->date; + } +} +?> diff --git a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php index 9d032e265e3b..9aa5bcd3be53 100644 --- a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php +++ b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php @@ -58,6 +58,8 @@ public function provideNamespacedClasses(): Iterator yield [__DIR__ . '/Fixture/keep_static_method.php.inc']; yield [__DIR__ . '/Fixture/keep_various_request.php.inc']; yield [__DIR__ . '/Fixture/instance_of.php.inc']; + + yield [__DIR__ . '/Fixture/import_root_namespace_classes_enabled.php.inc']; } public function provideFunctions(): Iterator diff --git a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php new file mode 100644 index 000000000000..70356e0305dc --- /dev/null +++ b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php @@ -0,0 +1,33 @@ +doTestFile($file); + } + + public function provideDataForTest(): iterable + { + yield [__DIR__ . '/Fixture/import_root_namespace_classes_disabled.php.inc']; + } + + protected function getRectorsWithConfiguration(): array + { + return [ + ImportFullyQualifiedNamesRector::class => [ + '$shouldImportRootNamespaceClasses' => false, + ], + ]; + } +} From dae17c98a0375898c5223eae06ba979d678959a7 Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Thu, 3 Oct 2019 00:50:05 +0200 Subject: [PATCH 3/6] Check for root namespace class differently. --- .../Rector/Namespace_/ImportFullyQualifiedNamesRector.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php index cf3b7989e6a6..0aeb0615b643 100644 --- a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php +++ b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php @@ -2,6 +2,7 @@ namespace Rector\CodingStyle\Rector\Namespace_; +use Nette\Utils\Strings; use PhpParser\Node; use PhpParser\Node\Name; use Rector\CodingStyle\Node\NameImporter; @@ -82,8 +83,11 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { // Importing root namespace classes (like \DateTime) is optional - if (!$this->shouldImportRootNamespaceClasses && $node instanceof Name && !$node->isQualified()) { - return null; + if (! $this->shouldImportRootNamespaceClasses) { + $name = $this->getName($node); + if (Strings::startsWith($name, '\\') && substr_count($name, '\\') === 1) { + return null; + } } $this->useAddingCommander->analyseFileInfoUseStatements($node); From 239ad3b99f3234321c50b70f9aa5727551e04209 Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Thu, 3 Oct 2019 01:01:09 +0200 Subject: [PATCH 4/6] Fix implementation. DocBlock still not handled. --- .../Rector/Namespace_/ImportFullyQualifiedNamesRector.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php index 0aeb0615b643..85c2334dfcb0 100644 --- a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php +++ b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php @@ -2,7 +2,6 @@ namespace Rector\CodingStyle\Rector\Namespace_; -use Nette\Utils\Strings; use PhpParser\Node; use PhpParser\Node\Name; use Rector\CodingStyle\Node\NameImporter; @@ -83,9 +82,9 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { // Importing root namespace classes (like \DateTime) is optional - if (! $this->shouldImportRootNamespaceClasses) { + if (! $this->shouldImportRootNamespaceClasses && $node instanceof Name) { $name = $this->getName($node); - if (Strings::startsWith($name, '\\') && substr_count($name, '\\') === 1) { + if ($name !== null && substr_count($name, '\\') === 0) { return null; } } From 205754067ca3c2dbdb3576a895aa32110d059409 Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Fri, 4 Oct 2019 12:55:50 +0200 Subject: [PATCH 5/6] Implement DocBlock support, simplify some code, make the fixture more bulletproof (one example of root namespace class, one example of non root namespace class). --- .../ImportFullyQualifiedNamesRector.php | 18 ++--- ...rt_root_namespace_classes_disabled.php.inc | 71 +++++++++++++++++++ .../NodeAnalyzer/DocBlockManipulator.php | 8 ++- .../NodeAnalyzer/DocBlockNameImporter.php | 14 +++- 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php index 85c2334dfcb0..32912c6ae938 100644 --- a/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php +++ b/packages/CodingStyle/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php @@ -81,23 +81,23 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - // Importing root namespace classes (like \DateTime) is optional - if (! $this->shouldImportRootNamespaceClasses && $node instanceof Name) { - $name = $this->getName($node); - if ($name !== null && substr_count($name, '\\') === 0) { - return null; - } - } - $this->useAddingCommander->analyseFileInfoUseStatements($node); if ($node instanceof Name) { + // Importing root namespace classes (like \DateTime) is optional + if (! $this->shouldImportRootNamespaceClasses) { + $name = $this->getName($node); + if ($name !== null && substr_count($name, '\\') === 0) { + return null; + } + } + return $this->nameImporter->importName($node); } // process doc blocks if ($this->shouldImportDocBlocks) { - $this->docBlockManipulator->importNames($node); + $this->docBlockManipulator->importNames($node, $this->shouldImportRootNamespaceClasses); return $node; } diff --git a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc index 9e78a31299a7..658e32bfb4e5 100644 --- a/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc +++ b/packages/CodingStyle/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture/import_root_namespace_classes_disabled.php.inc @@ -9,12 +9,21 @@ final class ImportRootNamespaceClassesDisabled */ private $date; + /** + * @var \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Response + */ + private $response; + public function __construct() { /** @var \DateTime $currentDate */ $currentDate = new \DateTime(); + /** @var \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Response $response */ + $response = new \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Response(); + $this->date = $currentDate; + $this->response = $response; } public function setDate(?\DateTime $date): void @@ -26,4 +35,66 @@ final class ImportRootNamespaceClassesDisabled { return $this->date; } + + public function setResponse(?\Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Response $response): void + { + $this->response = $response; + } + + public function getResponse(): ?\Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Response + { + return $this->response; + } +} +?> +----- +date = $currentDate; + $this->response = $response; + } + + public function setDate(?\DateTime $date): void + { + $this->date = $date; + } + + public function getDate(): ?\DateTime + { + return $this->date; + } + + public function setResponse(?Response $response): void + { + $this->response = $response; + } + + public function getResponse(): ?Response + { + return $this->response; + } } +?> diff --git a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php index c6df8894b14d..73dc30ffa445 100644 --- a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php +++ b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php @@ -345,14 +345,18 @@ public function replaceTagByAnother(PhpDocNode $phpDocNode, string $oldTag, stri } } - public function importNames(Node $node): void + public function importNames(Node $node, bool $shouldImportRootNamespaceClasses = true): void { if ($node->getDocComment() === null) { return; } $phpDocInfo = $this->createPhpDocInfoFromNode($node); - $hasNodeChanged = $this->docBlockNameImporter->importNames($phpDocInfo, $node); + $hasNodeChanged = $this->docBlockNameImporter->importNames( + $phpDocInfo, + $node, + $shouldImportRootNamespaceClasses + ); if ($hasNodeChanged) { $this->updateNodeWithPhpDocInfo($node, $phpDocInfo); diff --git a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php index 926aa2b08f06..4c5287becb5c 100644 --- a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php +++ b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php @@ -77,12 +77,16 @@ public function __construct( $this->importSkipper = $importSkipper; } - public function importNames(PhpDocInfo $phpDocInfo, Node $phpParserNode): bool - { + public function importNames( + PhpDocInfo $phpDocInfo, + Node $phpParserNode, + bool $shouldImportRootNamespaceClasses = true + ): bool { $phpDocNode = $phpDocInfo->getPhpDocNode(); $this->phpDocNodeTraverser->traverseWithCallable($phpDocNode, function (PhpDocParserNode $docNode) use ( - $phpParserNode + $phpParserNode, + $shouldImportRootNamespaceClasses ): PhpDocParserNode { if (! $docNode instanceof IdentifierTypeNode) { return $docNode; @@ -93,6 +97,10 @@ public function importNames(PhpDocInfo $phpDocInfo, Node $phpParserNode): bool return $docNode; } + if (! $shouldImportRootNamespaceClasses && substr_count($staticType->getClassName(), '\\') === 0) { + return $docNode; + } + return $this->processFqnNameImport($phpParserNode, $docNode, $staticType); }); From 8ffce14a6447d6c32da21a5903e731451980713c Mon Sep 17 00:00:00 2001 From: Dorian Villet Date: Fri, 4 Oct 2019 12:57:41 +0200 Subject: [PATCH 6/6] Add a comment. --- .../src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php index 4c5287becb5c..dea930b72d59 100644 --- a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php +++ b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockNameImporter.php @@ -97,6 +97,7 @@ public function importNames( return $docNode; } + // Importing root namespace classes (like \DateTime) is optional if (! $shouldImportRootNamespaceClasses && substr_count($staticType->getClassName(), '\\') === 0) { return $docNode; }