Skip to content

Commit b2213fd

Browse files
authored
[Refactor] Move bloated logic on NameImportingPostRector into ClassNameImportSkipper and NameImporter (#6267)
1 parent fd4f6d0 commit b2213fd

File tree

3 files changed

+87
-94
lines changed

3 files changed

+87
-94
lines changed

rules/CodingStyle/ClassNameImport/ClassNameImportSkipper.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66

77
use PhpParser\Node;
88
use PhpParser\Node\Identifier;
9+
use PhpParser\Node\Name;
910
use PhpParser\Node\Name\FullyQualified;
1011
use PhpParser\Node\Stmt\GroupUse;
1112
use PhpParser\Node\Stmt\Use_;
1213
use PhpParser\Node\Stmt\UseUse;
1314
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
15+
use Rector\Configuration\Option;
16+
use Rector\Configuration\Parameter\SimpleParameterProvider;
1417
use Rector\Naming\Naming\UseImportsResolver;
18+
use Rector\NodeTypeResolver\Node\AttributeKey;
1519
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
1620
use Rector\ValueObject\Application\File;
1721

@@ -40,13 +44,49 @@ public function shouldSkipNameForFullyQualifiedObjectType(
4044
return false;
4145
}
4246

47+
private function shouldSkipShortName(FullyQualified $fullyQualified): bool
48+
{
49+
// is scalar name?
50+
if (in_array($fullyQualified->toLowerString(), ['true', 'false', 'bool'], true)) {
51+
return true;
52+
}
53+
54+
if ($fullyQualified->isSpecialClassName()) {
55+
return true;
56+
}
57+
58+
if ($this->isFunctionOrConstantImport($fullyQualified)) {
59+
return true;
60+
}
61+
62+
// Importing root namespace classes (like \DateTime) is optional
63+
return ! SimpleParameterProvider::provideBoolParameter(Option::IMPORT_SHORT_CLASSES);
64+
}
65+
66+
private function isFunctionOrConstantImport(FullyQualified $fullyQualified): bool
67+
{
68+
if ($fullyQualified->getAttribute(AttributeKey::IS_CONSTFETCH_NAME) === true) {
69+
return true;
70+
}
71+
72+
return $fullyQualified->getAttribute(AttributeKey::IS_FUNCCALL_NAME) === true;
73+
}
74+
4375
/**
4476
* @param array<Use_|GroupUse> $uses
4577
*/
4678
public function shouldSkipName(FullyQualified $fullyQualified, array $uses): bool
4779
{
48-
if (substr_count($fullyQualified->toCodeString(), '\\') <= 1) {
49-
return false;
80+
if (substr_count($fullyQualified->toCodeString(), '\\') === 1) {
81+
return $this->shouldSkipShortName($fullyQualified);
82+
}
83+
84+
// verify long name, as short name verify may conflict
85+
// see test PR: https://github.com/rectorphp/rector-src/pull/6208
86+
// ref https://3v4l.org/21H5j vs https://3v4l.org/GIHSB
87+
$originalName = $fullyQualified->getAttribute(AttributeKey::ORIGINAL_NAME);
88+
if ($originalName instanceof Name && $originalName->getLast() === $originalName->toString()) {
89+
return true;
5090
}
5191

5292
$stringName = $fullyQualified->toString();

rules/CodingStyle/Node/NameImporter.php

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Rector\CodingStyle\Node;
66

7+
use PhpParser\Node\Identifier;
78
use PhpParser\Node\Name;
89
use PhpParser\Node\Name\FullyQualified;
10+
use PhpParser\Node\Stmt\GroupUse;
11+
use PhpParser\Node\Stmt\Use_;
912
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
10-
use Rector\Configuration\Option;
11-
use Rector\Configuration\Parameter\SimpleParameterProvider;
13+
use Rector\Naming\Naming\AliasNameResolver;
1214
use Rector\NodeTypeResolver\Node\AttributeKey;
1315
use Rector\PostRector\Collector\UseNodesToAddCollector;
1416
use Rector\StaticTypeMapper\PhpParser\FullyQualifiedNodeMapper;
@@ -20,13 +22,17 @@
2022
public function __construct(
2123
private ClassNameImportSkipper $classNameImportSkipper,
2224
private FullyQualifiedNodeMapper $fullyQualifiedNodeMapper,
23-
private UseNodesToAddCollector $useNodesToAddCollector
25+
private UseNodesToAddCollector $useNodesToAddCollector,
26+
private AliasNameResolver $aliasNameResolver
2427
) {
2528
}
2629

27-
public function importName(FullyQualified $fullyQualified, File $file): ?Name
30+
/**
31+
* @param array<Use_|GroupUse> $currentUses
32+
*/
33+
public function importName(FullyQualified $fullyQualified, File $file, array $currentUses): ?Name
2834
{
29-
if ($this->shouldSkipName($fullyQualified)) {
35+
if ($this->classNameImportSkipper->shouldSkipName($fullyQualified, $currentUses)) {
3036
return null;
3137
}
3238

@@ -35,36 +41,55 @@ public function importName(FullyQualified $fullyQualified, File $file): ?Name
3541
return null;
3642
}
3743

38-
return $this->importNameAndCollectNewUseStatement($file, $fullyQualified, $staticType);
44+
return $this->importNameAndCollectNewUseStatement($file, $fullyQualified, $staticType, $currentUses);
3945
}
4046

41-
private function shouldSkipName(FullyQualified $fullyQualified): bool
47+
/**
48+
* @param array<Use_|GroupUse> $currentUses
49+
*/
50+
private function resolveNameInUse(FullyQualified $fullyQualified, array $currentUses): ?Name
4251
{
43-
// is scalar name?
44-
if (in_array($fullyQualified->toLowerString(), ['true', 'false', 'bool'], true)) {
45-
return true;
52+
$aliasName = $this->aliasNameResolver->resolveByName($fullyQualified, $currentUses);
53+
if (is_string($aliasName)) {
54+
return new Name($aliasName);
4655
}
4756

48-
if ($this->isFunctionOrConstantImportWithSingleName($fullyQualified)) {
49-
return true;
57+
if (substr_count($fullyQualified->toCodeString(), '\\') === 1) {
58+
return null;
5059
}
5160

52-
// Importing root namespace classes (like \DateTime) is optional
53-
if (! SimpleParameterProvider::provideBoolParameter(Option::IMPORT_SHORT_CLASSES)) {
54-
$stringName = $fullyQualified->toString();
55-
if (substr_count($stringName, '\\') === 0) {
56-
return true;
61+
$lastName = $fullyQualified->getLast();
62+
foreach ($currentUses as $currentUse) {
63+
foreach ($currentUse->uses as $useUse) {
64+
if ($useUse->name->getLast() !== $lastName) {
65+
continue;
66+
}
67+
68+
if ($useUse->alias instanceof Identifier && $useUse->alias->toString() !== $lastName) {
69+
return new Name($lastName);
70+
}
5771
}
5872
}
5973

60-
return false;
74+
return null;
6175
}
6276

77+
/**
78+
* @param array<Use_|GroupUse> $currentUses
79+
*/
6380
private function importNameAndCollectNewUseStatement(
6481
File $file,
6582
FullyQualified $fullyQualified,
66-
FullyQualifiedObjectType $fullyQualifiedObjectType
83+
FullyQualifiedObjectType $fullyQualifiedObjectType,
84+
array $currentUses
6785
): ?Name {
86+
// make use of existing use import
87+
$nameInUse = $this->resolveNameInUse($fullyQualified, $currentUses);
88+
if ($nameInUse instanceof Name) {
89+
$nameInUse->setAttribute(AttributeKey::NAMESPACED_NAME, $fullyQualified->toString());
90+
return $nameInUse;
91+
}
92+
6893
// the same end is already imported → skip
6994
if ($this->classNameImportSkipper->shouldSkipNameForFullyQualifiedObjectType(
7095
$file,
@@ -86,19 +111,6 @@ private function importNameAndCollectNewUseStatement(
86111
return $fullyQualifiedObjectType->getShortNameNode();
87112
}
88113

89-
private function isFunctionOrConstantImportWithSingleName(FullyQualified $fullyQualified): bool
90-
{
91-
if ($fullyQualified->getAttribute(AttributeKey::IS_CONSTFETCH_NAME) === true) {
92-
return count($fullyQualified->getParts()) === 1;
93-
}
94-
95-
if ($fullyQualified->getAttribute(AttributeKey::IS_FUNCCALL_NAME) === true) {
96-
return count($fullyQualified->getParts()) === 1;
97-
}
98-
99-
return false;
100-
}
101-
102114
private function addUseImport(
103115
File $file,
104116
FullyQualified $fullyQualified,

src/PostRector/Rector/NameImportingPostRector.php

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
namespace Rector\PostRector\Rector;
66

77
use PhpParser\Node;
8-
use PhpParser\Node\Identifier;
9-
use PhpParser\Node\Name;
108
use PhpParser\Node\Name\FullyQualified;
119
use PhpParser\Node\Stmt;
1210
use PhpParser\Node\Stmt\GroupUse;
1311
use PhpParser\Node\Stmt\Use_;
14-
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
1512
use Rector\CodingStyle\Node\NameImporter;
16-
use Rector\Naming\Naming\AliasNameResolver;
1713
use Rector\Naming\Naming\UseImportsResolver;
18-
use Rector\NodeTypeResolver\Node\AttributeKey;
1914
use Rector\PostRector\Guard\AddUseStatementGuard;
2015

2116
final class NameImportingPostRector extends AbstractPostRector
@@ -27,9 +22,7 @@ final class NameImportingPostRector extends AbstractPostRector
2722

2823
public function __construct(
2924
private readonly NameImporter $nameImporter,
30-
private readonly ClassNameImportSkipper $classNameImportSkipper,
3125
private readonly UseImportsResolver $useImportsResolver,
32-
private readonly AliasNameResolver $aliasNameResolver,
3326
private readonly AddUseStatementGuard $addUseStatementGuard
3427
) {
3528
}
@@ -46,32 +39,7 @@ public function enterNode(Node $node): Node|int|null
4639
return null;
4740
}
4841

49-
if ($node->isSpecialClassName()) {
50-
return null;
51-
}
52-
53-
// verify long name, as short name verify may conflict
54-
// see test PR: https://github.com/rectorphp/rector-src/pull/6208
55-
// ref https://3v4l.org/21H5j vs https://3v4l.org/GIHSB
56-
if (substr_count($node->toCodeString(), '\\') > 1) {
57-
$originalName = $node->getAttribute(AttributeKey::ORIGINAL_NAME);
58-
if ($originalName instanceof Name && $originalName->getLast() === $originalName->toString()) {
59-
return null;
60-
}
61-
}
62-
63-
if ($this->classNameImportSkipper->shouldSkipName($node, $this->currentUses)) {
64-
return null;
65-
}
66-
67-
// make use of existing use import
68-
$nameInUse = $this->resolveNameInUse($node);
69-
if ($nameInUse instanceof Name) {
70-
$nameInUse->setAttribute(AttributeKey::NAMESPACED_NAME, $node->toString());
71-
return $nameInUse;
72-
}
73-
74-
return $this->nameImporter->importName($node, $this->getFile());
42+
return $this->nameImporter->importName($node, $this->getFile(), $this->currentUses);
7543
}
7644

7745
/**
@@ -81,31 +49,4 @@ public function shouldTraverse(array $stmts): bool
8149
{
8250
return $this->addUseStatementGuard->shouldTraverse($stmts, $this->getFile()->getFilePath());
8351
}
84-
85-
private function resolveNameInUse(FullyQualified $fullyQualified): null|Name
86-
{
87-
$aliasName = $this->aliasNameResolver->resolveByName($fullyQualified, $this->currentUses);
88-
if (is_string($aliasName)) {
89-
return new Name($aliasName);
90-
}
91-
92-
if (substr_count($fullyQualified->toCodeString(), '\\') === 1) {
93-
return null;
94-
}
95-
96-
$lastName = $fullyQualified->getLast();
97-
foreach ($this->currentUses as $currentUse) {
98-
foreach ($currentUse->uses as $useUse) {
99-
if ($useUse->name->getLast() !== $lastName) {
100-
continue;
101-
}
102-
103-
if ($useUse->alias instanceof Identifier && $useUse->alias->toString() !== $lastName) {
104-
return new Name($lastName);
105-
}
106-
}
107-
}
108-
109-
return null;
110-
}
11152
}

0 commit comments

Comments
 (0)