2019-10-13 07:59:52 +02:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2019-09-28 14:08:08 +02:00
|
|
|
namespace Rector\CodingStyle\Node;
|
|
|
|
|
2021-01-22 11:24:16 +02:00
|
|
|
use PhpParser\Node;
|
2019-10-03 08:53:23 +02:00
|
|
|
use PhpParser\Node\Expr\ConstFetch;
|
2019-09-28 14:08:08 +02:00
|
|
|
use PhpParser\Node\Expr\FuncCall;
|
|
|
|
use PhpParser\Node\Name;
|
|
|
|
use PhpParser\Node\Stmt\Namespace_;
|
2021-06-14 17:05:09 +00:00
|
|
|
use PhpParser\Node\Stmt\Use_;
|
2019-09-28 14:08:08 +02:00
|
|
|
use PhpParser\Node\Stmt\UseUse;
|
2021-02-28 08:47:48 +01:00
|
|
|
use PHPStan\Reflection\ReflectionProvider;
|
2020-11-20 13:37:53 +00:00
|
|
|
use Rector\CodingStyle\ClassNameImport\AliasUsesResolver;
|
|
|
|
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
|
2020-02-06 22:48:18 +01:00
|
|
|
use Rector\Core\Configuration\Option;
|
2021-07-21 13:46:30 +00:00
|
|
|
use Rector\Core\ValueObject\Application\File;
|
2020-02-09 23:47:00 +01:00
|
|
|
use Rector\NodeNameResolver\NodeNameResolver;
|
2019-09-28 14:08:08 +02:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
2020-03-31 19:32:54 +02:00
|
|
|
use Rector\PostRector\Collector\UseNodesToAddCollector;
|
2020-02-10 10:17:05 +01:00
|
|
|
use Rector\StaticTypeMapper\StaticTypeMapper;
|
2020-12-24 17:31:24 +01:00
|
|
|
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
2021-11-20 10:43:40 +00:00
|
|
|
use RectorPrefix20211120\Symplify\PackageBuilder\Parameter\ParameterProvider;
|
2019-09-28 14:08:08 +02:00
|
|
|
final class NameImporter
|
|
|
|
{
|
2020-02-01 17:04:38 +01:00
|
|
|
/**
|
|
|
|
* @var string[]
|
|
|
|
*/
|
|
|
|
private $aliasedUses = [];
|
2019-09-28 14:08:08 +02:00
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\CodingStyle\ClassNameImport\AliasUsesResolver
|
2019-09-28 14:08:08 +02:00
|
|
|
*/
|
|
|
|
private $aliasUsesResolver;
|
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper
|
2019-09-28 14:08:08 +02:00
|
|
|
*/
|
2020-11-20 13:37:53 +00:00
|
|
|
private $classNameImportSkipper;
|
2019-11-08 22:52:23 +01:00
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\NodeNameResolver\NodeNameResolver
|
2019-11-08 22:52:23 +01:00
|
|
|
*/
|
2020-02-09 12:31:31 +01:00
|
|
|
private $nodeNameResolver;
|
2019-11-08 22:52:23 +01:00
|
|
|
/**
|
2021-08-23 00:20:32 +00:00
|
|
|
* @var \Symplify\PackageBuilder\Parameter\ParameterProvider
|
2019-11-08 22:52:23 +01:00
|
|
|
*/
|
|
|
|
private $parameterProvider;
|
2020-03-31 19:32:54 +02:00
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\StaticTypeMapper\StaticTypeMapper
|
|
|
|
*/
|
|
|
|
private $staticTypeMapper;
|
|
|
|
/**
|
|
|
|
* @var \Rector\PostRector\Collector\UseNodesToAddCollector
|
2020-03-31 19:32:54 +02:00
|
|
|
*/
|
|
|
|
private $useNodesToAddCollector;
|
2021-02-28 08:47:48 +01:00
|
|
|
/**
|
2021-08-23 00:20:32 +00:00
|
|
|
* @var \PHPStan\Reflection\ReflectionProvider
|
2021-02-28 08:47:48 +01:00
|
|
|
*/
|
|
|
|
private $reflectionProvider;
|
2021-11-20 10:43:40 +00:00
|
|
|
public function __construct(\Rector\CodingStyle\ClassNameImport\AliasUsesResolver $aliasUsesResolver, \Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper $classNameImportSkipper, \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \RectorPrefix20211120\Symplify\PackageBuilder\Parameter\ParameterProvider $parameterProvider, \Rector\StaticTypeMapper\StaticTypeMapper $staticTypeMapper, \Rector\PostRector\Collector\UseNodesToAddCollector $useNodesToAddCollector, \PHPStan\Reflection\ReflectionProvider $reflectionProvider)
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2019-09-28 14:08:08 +02:00
|
|
|
$this->aliasUsesResolver = $aliasUsesResolver;
|
2020-11-20 13:37:53 +00:00
|
|
|
$this->classNameImportSkipper = $classNameImportSkipper;
|
2020-02-09 12:31:31 +01:00
|
|
|
$this->nodeNameResolver = $nodeNameResolver;
|
2019-11-08 22:52:23 +01:00
|
|
|
$this->parameterProvider = $parameterProvider;
|
2021-05-10 23:39:21 +00:00
|
|
|
$this->staticTypeMapper = $staticTypeMapper;
|
2020-03-31 19:32:54 +02:00
|
|
|
$this->useNodesToAddCollector = $useNodesToAddCollector;
|
2021-02-28 08:47:48 +01:00
|
|
|
$this->reflectionProvider = $reflectionProvider;
|
2019-09-28 14:08:08 +02:00
|
|
|
}
|
2021-06-14 17:05:09 +00:00
|
|
|
/**
|
|
|
|
* @param Use_[] $uses
|
|
|
|
*/
|
2021-07-21 13:46:30 +00:00
|
|
|
public function importName(\PhpParser\Node\Name $name, \Rector\Core\ValueObject\Application\File $file, array $uses) : ?\PhpParser\Node\Name
|
2019-09-28 14:08:08 +02:00
|
|
|
{
|
2019-11-08 22:29:15 +01:00
|
|
|
if ($this->shouldSkipName($name)) {
|
|
|
|
return null;
|
|
|
|
}
|
2021-06-14 17:05:09 +00:00
|
|
|
if ($this->classNameImportSkipper->isShortNameInUseStatement($name, $uses)) {
|
2020-12-07 19:20:59 +07:00
|
|
|
return null;
|
|
|
|
}
|
2019-09-28 14:08:08 +02:00
|
|
|
$staticType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($name);
|
2021-05-10 22:23:08 +00:00
|
|
|
if (!$staticType instanceof \Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType) {
|
2019-09-28 14:08:08 +02:00
|
|
|
return null;
|
|
|
|
}
|
2021-11-14 09:32:59 +00:00
|
|
|
$className = $staticType->getClassName();
|
|
|
|
// class has \, no need to search in aliases, mark aliasedUses as empty
|
|
|
|
$this->aliasedUses = \strpos($className, '\\') !== \false ? [] : $this->aliasUsesResolver->resolveFromStmts($uses);
|
|
|
|
return $this->importNameAndCollectNewUseStatement($file, $name, $staticType, $className);
|
2019-09-28 14:08:08 +02:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
private function shouldSkipName(\PhpParser\Node\Name $name) : bool
|
2019-09-28 14:08:08 +02:00
|
|
|
{
|
2021-05-10 22:23:08 +00:00
|
|
|
$virtualNode = $name->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::VIRTUAL_NODE);
|
2020-10-26 21:03:26 +07:00
|
|
|
if ($virtualNode) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2019-09-28 14:08:08 +02:00
|
|
|
}
|
2020-02-01 17:04:38 +01:00
|
|
|
// is scalar name?
|
2021-05-09 20:15:43 +00:00
|
|
|
if (\in_array($name->toLowerString(), ['true', 'false', 'bool'], \true)) {
|
|
|
|
return \true;
|
2020-02-01 17:04:38 +01:00
|
|
|
}
|
2020-05-13 09:57:21 +02:00
|
|
|
// namespace <name>
|
|
|
|
// use <name>;
|
2020-02-01 17:04:38 +01:00
|
|
|
if ($this->isNamespaceOrUseImportName($name)) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2019-10-30 10:49:07 +01:00
|
|
|
}
|
2020-02-01 17:04:38 +01:00
|
|
|
if ($this->isFunctionOrConstantImportWithSingleName($name)) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2020-02-01 17:04:38 +01:00
|
|
|
}
|
|
|
|
// Importing root namespace classes (like \DateTime) is optional
|
2021-06-14 17:05:09 +00:00
|
|
|
if (!$this->parameterProvider->provideBoolParameter(\Rector\Core\Configuration\Option::IMPORT_SHORT_CLASSES)) {
|
2020-02-09 12:31:31 +01:00
|
|
|
$name = $this->nodeNameResolver->getName($name);
|
2021-05-09 20:15:43 +00:00
|
|
|
if ($name !== null && \substr_count($name, '\\') === 0) {
|
|
|
|
return \true;
|
2020-02-01 17:04:38 +01:00
|
|
|
}
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2019-10-30 10:49:07 +01:00
|
|
|
}
|
2021-11-14 09:32:59 +00:00
|
|
|
private function importNameAndCollectNewUseStatement(\Rector\Core\ValueObject\Application\File $file, \PhpParser\Node\Name $name, \Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType $fullyQualifiedObjectType, string $className) : ?\PhpParser\Node\Name
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2019-09-28 14:08:08 +02:00
|
|
|
// the same end is already imported → skip
|
2021-07-21 13:46:30 +00:00
|
|
|
if ($this->classNameImportSkipper->shouldSkipNameForFullyQualifiedObjectType($file, $name, $fullyQualifiedObjectType)) {
|
2019-09-28 14:08:08 +02:00
|
|
|
return null;
|
|
|
|
}
|
2021-07-21 13:46:30 +00:00
|
|
|
if ($this->useNodesToAddCollector->isShortImported($file, $fullyQualifiedObjectType)) {
|
|
|
|
if ($this->useNodesToAddCollector->isImportShortable($file, $fullyQualifiedObjectType)) {
|
2019-09-28 14:08:08 +02:00
|
|
|
return $fullyQualifiedObjectType->getShortNameNode();
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2021-07-21 13:46:30 +00:00
|
|
|
$this->addUseImport($file, $name, $fullyQualifiedObjectType);
|
2021-11-14 09:32:59 +00:00
|
|
|
if ($this->aliasedUses === []) {
|
|
|
|
return $fullyQualifiedObjectType->getShortNameNode();
|
|
|
|
}
|
2019-09-28 14:08:08 +02:00
|
|
|
// possibly aliased
|
2021-03-05 17:55:40 +07:00
|
|
|
foreach ($this->aliasedUses as $aliasedUse) {
|
2021-11-14 09:32:59 +00:00
|
|
|
if ($className === $aliasedUse) {
|
2019-09-28 14:08:08 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $fullyQualifiedObjectType->getShortNameNode();
|
|
|
|
}
|
2020-02-01 17:04:38 +01:00
|
|
|
/**
|
|
|
|
* Skip:
|
|
|
|
* - namespace name
|
|
|
|
* - use import name
|
|
|
|
*/
|
2021-05-10 22:23:08 +00:00
|
|
|
private function isNamespaceOrUseImportName(\PhpParser\Node\Name $name) : bool
|
2019-09-28 14:08:08 +02:00
|
|
|
{
|
2021-05-10 22:23:08 +00:00
|
|
|
$parentNode = $name->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE);
|
|
|
|
if ($parentNode instanceof \PhpParser\Node\Stmt\Namespace_) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2019-09-28 14:08:08 +02:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
return $parentNode instanceof \PhpParser\Node\Stmt\UseUse;
|
2019-09-28 14:08:08 +02:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
private function isFunctionOrConstantImportWithSingleName(\PhpParser\Node\Name $name) : bool
|
2019-11-08 14:38:30 +01:00
|
|
|
{
|
2021-05-10 22:23:08 +00:00
|
|
|
$parentNode = $name->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE);
|
2021-01-22 11:24:16 +02:00
|
|
|
$fullName = $name->toString();
|
2021-05-10 22:23:08 +00:00
|
|
|
$autoImportNames = $this->parameterProvider->provideParameter(\Rector\Core\Configuration\Option::AUTO_IMPORT_NAMES);
|
2021-05-29 22:10:59 +00:00
|
|
|
if ($autoImportNames && !$parentNode instanceof \PhpParser\Node && \strpos($fullName, '\\') === \false && $this->reflectionProvider->hasFunction(new \PhpParser\Node\Name($fullName), null)) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2021-01-22 11:24:16 +02:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
if ($parentNode instanceof \PhpParser\Node\Expr\ConstFetch) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \count($name->parts) === 1;
|
2019-11-08 22:52:23 +01:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
if ($parentNode instanceof \PhpParser\Node\Expr\FuncCall) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \count($name->parts) === 1;
|
2021-02-21 16:32:45 +07:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2020-02-01 17:04:38 +01:00
|
|
|
}
|
2021-07-21 13:46:30 +00:00
|
|
|
private function addUseImport(\Rector\Core\ValueObject\Application\File $file, \PhpParser\Node\Name $name, \Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType $fullyQualifiedObjectType) : void
|
2020-04-26 02:57:47 +02:00
|
|
|
{
|
2021-07-21 13:46:30 +00:00
|
|
|
if ($this->useNodesToAddCollector->hasImport($file, $name, $fullyQualifiedObjectType)) {
|
2020-04-26 02:57:47 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
$parentNode = $name->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE);
|
|
|
|
if ($parentNode instanceof \PhpParser\Node\Expr\FuncCall) {
|
2021-11-05 11:26:12 +00:00
|
|
|
$this->useNodesToAddCollector->addFunctionUseImport($fullyQualifiedObjectType);
|
2020-04-26 02:57:47 +02:00
|
|
|
} else {
|
2021-06-22 10:43:16 +00:00
|
|
|
$this->useNodesToAddCollector->addUseImport($fullyQualifiedObjectType);
|
2020-04-26 02:57:47 +02:00
|
|
|
}
|
|
|
|
}
|
2019-09-28 14:08:08 +02:00
|
|
|
}
|