2021-04-06 17:33:09 +00:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2021-04-06 17:33:09 +00:00
|
|
|
namespace Rector\NodeTypeResolver\PhpDocNodeVisitor;
|
|
|
|
|
|
|
|
use PhpParser\Node as PhpParserNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\Node;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
|
|
|
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
|
|
|
|
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
|
|
|
|
use Rector\Core\Configuration\Option;
|
|
|
|
use Rector\Core\Exception\ShouldNotHappenException;
|
|
|
|
use Rector\PostRector\Collector\UseNodesToAddCollector;
|
|
|
|
use Rector\StaticTypeMapper\StaticTypeMapper;
|
|
|
|
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
2021-06-18 17:14:06 +00:00
|
|
|
use RectorPrefix20210618\Symplify\PackageBuilder\Parameter\ParameterProvider;
|
|
|
|
use RectorPrefix20210618\Symplify\SimplePhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor;
|
|
|
|
final class NameImportingPhpDocNodeVisitor extends \RectorPrefix20210618\Symplify\SimplePhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor
|
2021-04-06 17:33:09 +00:00
|
|
|
{
|
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var PhpParserNode|null
|
|
|
|
*/
|
|
|
|
private $currentPhpParserNode;
|
|
|
|
/**
|
|
|
|
* @var \Rector\StaticTypeMapper\StaticTypeMapper
|
2021-04-06 17:33:09 +00:00
|
|
|
*/
|
|
|
|
private $staticTypeMapper;
|
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Symplify\PackageBuilder\Parameter\ParameterProvider
|
2021-04-06 17:33:09 +00:00
|
|
|
*/
|
|
|
|
private $parameterProvider;
|
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper
|
2021-04-06 17:33:09 +00:00
|
|
|
*/
|
|
|
|
private $classNameImportSkipper;
|
|
|
|
/**
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\PostRector\Collector\UseNodesToAddCollector
|
2021-04-06 17:33:09 +00:00
|
|
|
*/
|
|
|
|
private $useNodesToAddCollector;
|
2021-06-18 17:14:06 +00:00
|
|
|
public function __construct(\Rector\StaticTypeMapper\StaticTypeMapper $staticTypeMapper, \RectorPrefix20210618\Symplify\PackageBuilder\Parameter\ParameterProvider $parameterProvider, \Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper $classNameImportSkipper, \Rector\PostRector\Collector\UseNodesToAddCollector $useNodesToAddCollector)
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2021-04-06 17:33:09 +00:00
|
|
|
$this->staticTypeMapper = $staticTypeMapper;
|
|
|
|
$this->parameterProvider = $parameterProvider;
|
|
|
|
$this->classNameImportSkipper = $classNameImportSkipper;
|
|
|
|
$this->useNodesToAddCollector = $useNodesToAddCollector;
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
public function beforeTraverse(\PHPStan\PhpDocParser\Ast\Node $node) : void
|
2021-04-06 17:33:09 +00:00
|
|
|
{
|
|
|
|
if ($this->currentPhpParserNode === null) {
|
2021-05-10 22:23:08 +00:00
|
|
|
throw new \Rector\Core\Exception\ShouldNotHappenException('Set "$currentPhpParserNode" first');
|
2021-04-06 17:33:09 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
public function enterNode(\PHPStan\PhpDocParser\Ast\Node $node) : ?\PHPStan\PhpDocParser\Ast\Node
|
2021-04-06 17:33:09 +00:00
|
|
|
{
|
2021-05-10 22:23:08 +00:00
|
|
|
if (!$node instanceof \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode) {
|
2021-04-06 17:33:09 +00:00
|
|
|
return null;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
$staticType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($node, $this->currentPhpParserNode);
|
2021-05-10 22:23:08 +00:00
|
|
|
if (!$staticType instanceof \Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType) {
|
2021-04-06 17:33:09 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// Importing root namespace classes (like \DateTime) is optional
|
|
|
|
if ($this->shouldSkipShortClassName($staticType)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $this->processFqnNameImport($this->currentPhpParserNode, $node, $staticType);
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
public function setCurrentNode(\PhpParser\Node $phpParserNode) : void
|
2021-04-06 17:33:09 +00:00
|
|
|
{
|
|
|
|
$this->currentPhpParserNode = $phpParserNode;
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
private function processFqnNameImport(\PhpParser\Node $phpParserNode, \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode $identifierTypeNode, \Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType $fullyQualifiedObjectType) : ?\PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
|
|
|
if ($this->classNameImportSkipper->shouldSkipNameForFullyQualifiedObjectType($phpParserNode, $fullyQualifiedObjectType)) {
|
2021-04-06 17:33:09 +00:00
|
|
|
return $identifierTypeNode;
|
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
$parent = $identifierTypeNode->getAttribute(\Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey::PARENT);
|
|
|
|
if ($parent instanceof \PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode) {
|
2021-04-06 17:33:09 +00:00
|
|
|
// might break
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// should skip because its already used
|
|
|
|
if ($this->useNodesToAddCollector->isShortImported($phpParserNode, $fullyQualifiedObjectType)) {
|
|
|
|
if ($this->useNodesToAddCollector->isImportShortable($phpParserNode, $fullyQualifiedObjectType)) {
|
2021-05-10 22:23:08 +00:00
|
|
|
$newNode = new \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode($fullyQualifiedObjectType->getShortName());
|
2021-04-09 21:00:57 +00:00
|
|
|
if ($newNode->name !== $identifierTypeNode->name) {
|
|
|
|
return $newNode;
|
|
|
|
}
|
|
|
|
return $identifierTypeNode;
|
2021-04-06 17:33:09 +00:00
|
|
|
}
|
|
|
|
return $identifierTypeNode;
|
|
|
|
}
|
|
|
|
$this->useNodesToAddCollector->addUseImport($phpParserNode, $fullyQualifiedObjectType);
|
2021-05-10 22:23:08 +00:00
|
|
|
$newNode = new \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode($fullyQualifiedObjectType->getShortName());
|
2021-04-09 21:00:57 +00:00
|
|
|
if ($newNode->name !== $identifierTypeNode->name) {
|
|
|
|
return $newNode;
|
|
|
|
}
|
|
|
|
return $identifierTypeNode;
|
2021-04-06 17:33:09 +00:00
|
|
|
}
|
2021-05-10 22:23:08 +00:00
|
|
|
private function shouldSkipShortClassName(\Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType $fullyQualifiedObjectType) : bool
|
2021-04-06 17:33:09 +00:00
|
|
|
{
|
2021-05-10 22:23:08 +00:00
|
|
|
$importShortClasses = $this->parameterProvider->provideBoolParameter(\Rector\Core\Configuration\Option::IMPORT_SHORT_CLASSES);
|
2021-04-06 17:33:09 +00:00
|
|
|
if ($importShortClasses) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2021-04-06 17:33:09 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \substr_count($fullyQualifiedObjectType->getClassName(), '\\') === 0;
|
2021-04-06 17:33:09 +00:00
|
|
|
}
|
|
|
|
}
|