Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types=1);

namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;

final class SharedShortName
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;

class SameNamespacedClass
{
/**
* @return \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\SharedShortName
*/
public function run(): \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\SharedShortName
{
}
}

?>
-----
<?php

namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;

use Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\SharedShortName;
class SameNamespacedClass
{
/**
* @return SharedShortName
*/
public function run(): SharedShortName
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;

class SkipSameNamespacedUsedClass
{
/**
* @return \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\SharedShortName
*/
public function run(): SharedShortName
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,12 @@ public function test(string $file): void
$this->doTestFile($file);
}

public function provideFunctions(): Iterator
{
yield [__DIR__ . '/Fixture/import_function.php.inc'];
yield [__DIR__ . '/Fixture/import_function_no_class.php.inc'];
yield [__DIR__ . '/Fixture/import_return_doc.php.inc'];
}

public function provideNamespacedClasses(): Iterator
{
// same short class with namespace
yield [__DIR__ . '/Fixture/same_namespaced_class.php.inc'];
yield [__DIR__ . '/Fixture/skip_same_namespaced_used_class.php.inc'];

yield [__DIR__ . '/Fixture/fixture.php.inc'];
yield [__DIR__ . '/Fixture/double_import.php.inc'];
yield [__DIR__ . '/Fixture/double_import_with_existing.php.inc'];
Expand All @@ -52,6 +49,13 @@ public function provideNamespacedClasses(): Iterator
yield [__DIR__ . '/Fixture/instance_of.php.inc'];
}

public function provideFunctions(): Iterator
{
yield [__DIR__ . '/Fixture/import_function.php.inc'];
yield [__DIR__ . '/Fixture/import_function_no_class.php.inc'];
yield [__DIR__ . '/Fixture/import_return_doc.php.inc'];
}

protected function getRectorClass(): string
{
return ImportFullyQualifiedNamesRector::class;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types=1);

namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source;

final class SharedShortName
{

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Nette\Utils\Strings;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
Expand Down Expand Up @@ -40,10 +41,17 @@
use Rector\NodeTypeResolver\Php\ReturnTypeInfo;
use Rector\NodeTypeResolver\Php\VarTypeInfo;
use Rector\Php\TypeAnalyzer;
use Rector\PhpParser\Node\Resolver\NameResolver;
use Rector\PhpParser\Printer\BetterStandardPrinter;
use Rector\TypeDeclaration\ValueObject\IdentifierValueObject;

final class DocBlockManipulator
{
/**
* @var bool[][]
*/
private $usedShortNameByClasses = [];

/**
* @var PhpDocInfoFactory
*/
Expand Down Expand Up @@ -84,14 +92,26 @@ final class DocBlockManipulator
*/
private $useAddingCommander;

/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;

/**
* @var NameResolver
*/
private $nameResolver;

public function __construct(
PhpDocInfoFactory $phpDocInfoFactory,
PhpDocInfoPrinter $phpDocInfoPrinter,
TypeAnalyzer $typeAnalyzer,
AttributeAwareNodeFactory $attributeAwareNodeFactory,
StringsTypePhpDocNodeDecorator $stringsTypePhpDocNodeDecorator,
NodeTraverser $nodeTraverser,
UseAddingCommander $useAddingCommander
NameResolver $nameResolver,
UseAddingCommander $useAddingCommander,
BetterStandardPrinter $betterStandardPrinter
) {
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->phpDocInfoPrinter = $phpDocInfoPrinter;
Expand All @@ -100,6 +120,8 @@ public function __construct(
$this->stringsTypePhpDocNodeDecorator = $stringsTypePhpDocNodeDecorator;
$this->nodeTraverser = $nodeTraverser;
$this->useAddingCommander = $useAddingCommander;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->nameResolver = $nameResolver;
}

public function hasTag(Node $node, string $name): bool
Expand Down Expand Up @@ -689,9 +711,15 @@ private function processFqnNameImport(
// the name is already in the same namespace implicitly
$namespaceName = $node->getAttribute(AttributeKey::NAMESPACE_NAME);

// the class in the same namespace as differnt file can se used in this code, the short names would colide → skip
// the class in the same namespace as different file can se used in this code, the short names would colide → skip
if (class_exists($namespaceName . '\\' . $shortName)) {
return $attributeAwareNode;
if ($this->isCurrentNamespaceSameShortClassAlreadyUsed(
$node,
$namespaceName . '\\' . $shortName,
$shortName
)) {
return $attributeAwareNode;
}
}

if ($this->useAddingCommander->isShortImported($node, $fullyQualifiedName)) {
Expand Down Expand Up @@ -742,4 +770,38 @@ private function preslashFullyQualifiedNames($type): string

return implode($joinChar, $types);
}

private function isCurrentNamespaceSameShortClassAlreadyUsed(
Node $node,
string $fullyQualifiedName,
string $shortName
): bool {
/** @var ClassLike|null $classNode */
$classNode = $node->getAttribute(AttributeKey::CLASS_NODE);
if ($classNode === null) {
// cannot say, so rather yes
return true;
}

$className = $this->nameResolver->getName($classNode);

if (isset($this->usedShortNameByClasses[$className][$shortName])) {
return $this->usedShortNameByClasses[$className][$shortName];
}

$printedClass = $this->betterStandardPrinter->print($classNode->stmts);

// short with space " Type"| fqn
$shortNameOrFullyQualifiedNamePattern = sprintf(
'#(\s%s\b|\b%s\b)#',
preg_quote($shortName),
preg_quote($fullyQualifiedName)
);

$isShortClassUsed = (bool) Strings::match($printedClass, $shortNameOrFullyQualifiedNamePattern);

$this->usedShortNameByClasses[$className][$shortName] = $isShortClassUsed;

return $isShortClassUsed;
}
}
2 changes: 1 addition & 1 deletion rector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ parameters:
php_version_features: '7.1'

services:
# Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~
Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~