2020-02-10 09:17:05 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
2020-12-24 16:31:24 +00:00
|
|
|
namespace Rector\StaticTypeMapper\Naming;
|
2020-02-10 09:17:05 +00:00
|
|
|
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Stmt\Use_;
|
|
|
|
use PhpParser\Node\Stmt\UseUse;
|
|
|
|
use PHPStan\Analyser\NameScope;
|
2020-12-28 13:01:27 +00:00
|
|
|
use PHPStan\Type\Generic\TemplateTypeMap;
|
|
|
|
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
2020-02-10 09:17:05 +00:00
|
|
|
use Rector\Core\Exception\ShouldNotHappenException;
|
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
2020-12-28 13:01:27 +00:00
|
|
|
use Rector\StaticTypeMapper\StaticTypeMapper;
|
2020-02-10 09:17:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @see https://github.com/phpstan/phpstan-src/blob/8376548f76e2c845ae047e3010e873015b796818/src/Analyser/NameScope.php#L32
|
|
|
|
*/
|
|
|
|
final class NameScopeFactory
|
|
|
|
{
|
2020-12-28 13:01:27 +00:00
|
|
|
/**
|
|
|
|
* @var StaticTypeMapper
|
|
|
|
*/
|
|
|
|
private $staticTypeMapper;
|
|
|
|
|
|
|
|
public function createNameScopeFromNodeWithoutTemplateTypes(Node $node): NameScope
|
2020-02-10 09:17:05 +00:00
|
|
|
{
|
|
|
|
$namespace = $node->getAttribute(AttributeKey::NAMESPACE_NAME);
|
|
|
|
|
|
|
|
/** @var Use_[] $useNodes */
|
|
|
|
$useNodes = (array) $node->getAttribute(AttributeKey::USE_NODES);
|
|
|
|
|
|
|
|
$uses = $this->resolveUseNamesByAlias($useNodes);
|
|
|
|
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
|
|
|
|
|
|
|
|
return new NameScope($namespace, $uses, $className);
|
|
|
|
}
|
|
|
|
|
2020-12-28 13:01:27 +00:00
|
|
|
public function createNameScopeFromNode(Node $node): NameScope
|
|
|
|
{
|
|
|
|
$nameScope = $this->createNameScopeFromNodeWithoutTemplateTypes($node);
|
|
|
|
$templateTypeMap = $this->templateTemplateTypeMap($node);
|
|
|
|
|
|
|
|
return new NameScope(
|
|
|
|
$nameScope->getNamespace(),
|
|
|
|
$nameScope->getUses(),
|
|
|
|
$nameScope->getClassName(),
|
|
|
|
null,
|
|
|
|
$templateTypeMap
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setStaticTypeMapper(StaticTypeMapper $staticTypeMapper): void
|
|
|
|
{
|
|
|
|
$this->staticTypeMapper = $staticTypeMapper;
|
|
|
|
}
|
|
|
|
|
2020-02-10 09:17:05 +00:00
|
|
|
/**
|
|
|
|
* @param Use_[] $useNodes
|
2020-09-01 17:56:30 +00:00
|
|
|
* @return array<string, string>
|
2020-02-10 09:17:05 +00:00
|
|
|
*/
|
|
|
|
private function resolveUseNamesByAlias(array $useNodes): array
|
|
|
|
{
|
|
|
|
$useNamesByAlias = [];
|
|
|
|
|
|
|
|
foreach ($useNodes as $useNode) {
|
|
|
|
foreach ($useNode->uses as $useUse) {
|
|
|
|
/** @var UseUse $useUse */
|
2020-10-01 16:55:10 +00:00
|
|
|
$aliasName = $useUse->getAlias()
|
|
|
|
->name;
|
2020-02-10 09:17:05 +00:00
|
|
|
|
|
|
|
$useName = $useUse->name->toString();
|
|
|
|
if (! is_string($useName)) {
|
|
|
|
throw new ShouldNotHappenException();
|
|
|
|
}
|
|
|
|
|
2020-09-01 17:56:30 +00:00
|
|
|
// uses must be lowercase, as PHPStan lowercases it
|
|
|
|
$lowercasedAliasName = strtolower($aliasName);
|
|
|
|
|
|
|
|
$useNamesByAlias[$lowercasedAliasName] = $useName;
|
2020-02-10 09:17:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $useNamesByAlias;
|
|
|
|
}
|
2020-12-28 13:01:27 +00:00
|
|
|
|
|
|
|
private function templateTemplateTypeMap(Node $node): TemplateTypeMap
|
|
|
|
{
|
|
|
|
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
|
|
|
|
|
|
|
$templateTypes = [];
|
|
|
|
if ($phpDocInfo instanceof PhpDocInfo) {
|
|
|
|
foreach ($phpDocInfo->getTemplateTagValueNodes() as $templateTagValueNode) {
|
|
|
|
$phpstanType = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($templateTagValueNode, $node);
|
|
|
|
$templateTypes[$templateTagValueNode->name] = $phpstanType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new TemplateTypeMap($templateTypes);
|
|
|
|
}
|
2020-02-10 09:17:05 +00:00
|
|
|
}
|