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
7 changes: 6 additions & 1 deletion config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ parameters:
exclude_rectors: []
autoload_paths: []

# importing FQN names
auto_import_names: true
# e.g. import \DateTime
import_short_classes: true
# e.g. /** @var \Some\ClassHere */
import_doc_blocks: true

php_version_features: ~ # what PHP version should be used for features, local PHP version is used by default
file_extensions:
- php
- 'php'
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\UseUse;
use Rector\CodingStyle\Node\NameImporter;
use Rector\Configuration\Option;
use Rector\Contract\PhpParser\Node\CommanderInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
use Symplify\PackageBuilder\Parameter\ParameterProvider;

Expand Down Expand Up @@ -57,11 +55,6 @@ public function traverseNodes(array $nodes): array
return null;
}

// skip name of UseUse
if ($node->getAttribute(AttributeKey::PARENT_NODE) instanceof UseUse) {
return null;
}

return $this->nameImporter->importName($node);
});

Expand Down
51 changes: 43 additions & 8 deletions packages/CodingStyle/src/Node/NameImporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
use Rector\CodingStyle\Application\UseAddingCommander;
use Rector\CodingStyle\Imports\AliasUsesResolver;
use Rector\CodingStyle\Imports\ImportSkipper;
use Rector\Configuration\Option;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\PhpParser\Node\Resolver\NameResolver;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Symplify\PackageBuilder\Parameter\ParameterProvider;

final class NameImporter
{
Expand Down Expand Up @@ -43,34 +46,43 @@ final class NameImporter
*/
private $importSkipper;

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

/**
* @var ParameterProvider
*/
private $parameterProvider;

public function __construct(
StaticTypeMapper $staticTypeMapper,
AliasUsesResolver $aliasUsesResolver,
UseAddingCommander $useAddingCommander,
ImportSkipper $importSkipper
ImportSkipper $importSkipper,
NameResolver $nameResolver,
ParameterProvider $parameterProvider
) {
$this->staticTypeMapper = $staticTypeMapper;
$this->aliasUsesResolver = $aliasUsesResolver;
$this->useAddingCommander = $useAddingCommander;
$this->importSkipper = $importSkipper;
$this->nameResolver = $nameResolver;
$this->parameterProvider = $parameterProvider;
}

public function importName(Name $name): ?Name
{
if ($name->getAttribute('virtual_node')) {
if ($this->shouldSkipName($name)) {
return null;
}

$staticType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($name);

if (! $staticType instanceof FullyQualifiedObjectType) {
return null;
}

if ($this->shouldSkipName($name)) {
return null;
}

$this->aliasedUses = $this->aliasUsesResolver->resolveForNode($name);

return $this->importNameAndCollectNewUseStatement($name, $staticType);
Expand Down Expand Up @@ -146,10 +158,33 @@ private function addUseImport(Name $name, FullyQualifiedObjectType $fullyQualifi

private function shouldSkipName(Name $name): bool
{
if ($name->getAttribute('virtual_node')) {
return true;
}

// is scalar name?
if (in_array($name->toString(), ['true', 'false', 'bool'], true)) {
return true;
}

if ($this->isNamespaceOrUseImportName($name)) {
return true;
}

return $this->isFunctionOrConstantImportWithSingleName($name);
if ($this->isFunctionOrConstantImportWithSingleName($name)) {
return true;
}

// Importing root namespace classes (like \DateTime) is optional
$importShortClasses = $this->parameterProvider->provideParameter(Option::IMPORT_SHORT_CLASSES_PARAMETER);

if (! $importShortClasses) {
$name = $this->nameResolver->getName($name);
if ($name !== null && substr_count($name, '\\') === 0) {
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@

use PhpParser\Node;
use PhpParser\Node\Name;
use Rector\CodingStyle\Application\NameImportingCommander;
use Rector\CodingStyle\Node\NameImporter;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\ConfiguredCodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\Testing\PHPUnit\PHPUnitEnvironment;

/**
* @see \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\ImportFullyQualifiedNamesRectorTest
Expand All @@ -22,26 +23,23 @@ final class ImportFullyQualifiedNamesRector extends AbstractRector
/**
* @var bool
*/
private $shouldImportDocBlocks = true;
private $importDocBlocks = true;

/**
* @var bool
* @var NameImporter
*/
private $shouldImportRootNamespaceClasses = true;
private $nameImporter;

/**
* @var NameImporter
* @var bool
*/
private $nameImporter;
private $autoImportNames = false;

public function __construct(
NameImporter $nameImporter,
bool $shouldImportDocBlocks = true,
bool $shouldImportRootNamespaceClasses = true
) {
public function __construct(NameImporter $nameImporter, bool $importDocBlocks, bool $autoImportNames)
{
$this->nameImporter = $nameImporter;
$this->shouldImportDocBlocks = $shouldImportDocBlocks;
$this->shouldImportRootNamespaceClasses = $shouldImportRootNamespaceClasses;
$this->importDocBlocks = $importDocBlocks;
$this->autoImportNames = $autoImportNames;
}

public function getDefinition(): RectorDefinition
Expand Down Expand Up @@ -81,43 +79,6 @@ public function createDate()
}
PHP
),
new ConfiguredCodeSample(
<<<'PHP'
class SomeClass
{
public function create()
{
return SomeAnother\AnotherClass;
}

public function createDate()
{
return new \DateTime(); // this remains untouched
}
}
PHP
,
<<<'PHP'
use SomeAnother\AnotherClass;

class SomeClass
{
public function create()
{
return AnotherClass;
}

public function createDate()
{
return new \DateTime(); // this remains untouched
}
}
PHP
,
[
'$shouldImportRootNamespaceClasses' => false,
]
),
]);
}

Expand All @@ -134,23 +95,20 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
/** prevents duplicated run with @see NameImportingCommander */
if ($this->autoImportNames && ! PHPUnitEnvironment::isPHPUnitRun()) {
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->shouldImportRootNamespaceClasses);
if ($this->importDocBlocks) {
$this->docBlockManipulator->importNames($node);
return $node;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector;

use Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector;
use Rector\Configuration\Option;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class ImportRootNamespaceClassesDisabledTest extends AbstractRectorTestCase
Expand All @@ -14,6 +15,7 @@ final class ImportRootNamespaceClassesDisabledTest extends AbstractRectorTestCas
*/
public function test(string $file): void
{
$this->setParameter(Option::IMPORT_SHORT_CLASSES_PARAMETER, false);
$this->doTestFile($file);
}

Expand All @@ -22,15 +24,8 @@ public function provideDataForTest(): iterable
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureRoot');
}

/**
* @return mixed[]
*/
protected function getRectorsWithConfiguration(): array
protected function getRectorClass(): string
{
return [
ImportFullyQualifiedNamesRector::class => [
'$shouldImportRootNamespaceClasses' => false,
],
];
return ImportFullyQualifiedNamesRector::class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -375,18 +375,14 @@ public function replaceTagByAnother(PhpDocNode $phpDocNode, string $oldTag, stri
}
}

public function importNames(Node $node, bool $shouldImportRootNamespaceClasses = true): void
public function importNames(Node $node): void
{
if ($node->getDocComment() === null) {
return;
}

$phpDocInfo = $this->createPhpDocInfoFromNode($node);
$hasNodeChanged = $this->docBlockNameImporter->importNames(
$phpDocInfo,
$node,
$shouldImportRootNamespaceClasses
);
$hasNodeChanged = $this->docBlockNameImporter->importNames($phpDocInfo, $node);

if ($hasNodeChanged) {
$this->updateNodeWithPhpDocInfo($node, $phpDocInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\CodingStyle\Application\UseAddingCommander;
use Rector\CodingStyle\Imports\ImportSkipper;
use Rector\Configuration\Option;
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\PhpParser\Node\Resolver\NameResolver;
use Rector\PhpParser\Printer\BetterStandardPrinter;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Rector\PHPStan\Type\ShortenedObjectType;
use Symplify\PackageBuilder\Parameter\ParameterProvider;

final class DocBlockNameImporter
{
Expand Down Expand Up @@ -63,34 +65,37 @@ final class DocBlockNameImporter
*/
private $importSkipper;

/**
* @var ParameterProvider
*/
private $parameterProvider;

public function __construct(
PhpDocNodeTraverser $phpDocNodeTraverser,
StaticTypeMapper $staticTypeMapper,
UseAddingCommander $useAddingCommander,
NameResolver $nameResolver,
BetterStandardPrinter $betterStandardPrinter,
ImportSkipper $importSkipper
ImportSkipper $importSkipper,
ParameterProvider $parameterProvider
) {
$this->phpDocNodeTraverser = $phpDocNodeTraverser;
$this->staticTypeMapper = $staticTypeMapper;
$this->useAddingCommander = $useAddingCommander;
$this->nameResolver = $nameResolver;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->importSkipper = $importSkipper;
$this->parameterProvider = $parameterProvider;
}

public function importNames(
PhpDocInfo $phpDocInfo,
Node $phpParserNode,
bool $shouldImportRootNamespaceClasses = true
): bool {
public function importNames(PhpDocInfo $phpDocInfo, Node $phpParserNode): bool
{
$phpDocNode = $phpDocInfo->getPhpDocNode();

$this->hasPhpDocChanged = false;

$this->phpDocNodeTraverser->traverseWithCallable($phpDocNode, function (PhpDocParserNode $docNode) use (
$phpParserNode,
$shouldImportRootNamespaceClasses
$phpParserNode
): PhpDocParserNode {
if (! $docNode instanceof IdentifierTypeNode) {
return $docNode;
Expand All @@ -101,8 +106,9 @@ public function importNames(
return $docNode;
}

$importShortClasses = $this->parameterProvider->provideParameter(Option::IMPORT_SHORT_CLASSES_PARAMETER);
// Importing root namespace classes (like \DateTime) is optional
if (! $shouldImportRootNamespaceClasses && substr_count($staticType->getClassName(), '\\') === 0) {
if (! $importShortClasses && substr_count($staticType->getClassName(), '\\') === 0) {
return $docNode;
}

Expand Down
Loading