*/
private $shortNamesByFilePath = [];
public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, UseImportNameMatcher $useImportNameMatcher, PhpDocInfoFactory $phpDocInfoFactory)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
$this->betterNodeFinder = $betterNodeFinder;
$this->useImportNameMatcher = $useImportNameMatcher;
$this->phpDocInfoFactory = $phpDocInfoFactory;
}
/**
* @return array
*/
public function resolveFromFile(File $file) : array
{
$filePath = $file->getFilePath();
if (isset($this->shortNamesByFilePath[$filePath])) {
return $this->shortNamesByFilePath[$filePath];
}
$shortNamesToFullyQualifiedNames = $this->resolveForStmts($file->getNewStmts());
$this->shortNamesByFilePath[$filePath] = $shortNamesToFullyQualifiedNames;
return $shortNamesToFullyQualifiedNames;
}
/**
* Collects all "class ", "trait " and "interface "
* @return string[]
*/
public function resolveShortClassLikeNames(File $file) : array
{
$newStmts = $file->getNewStmts();
/** @var Namespace_[]|FileWithoutNamespace[] $namespaces */
$namespaces = \array_filter($newStmts, static function (Stmt $stmt) : bool {
return $stmt instanceof Namespace_ || $stmt instanceof FileWithoutNamespace;
});
if (\count($namespaces) !== 1) {
// only handle single namespace nodes
return [];
}
$namespace = \current($namespaces);
/** @var ClassLike[] $classLikes */
$classLikes = $this->betterNodeFinder->findInstanceOf($namespace->stmts, ClassLike::class);
$shortClassLikeNames = [];
foreach ($classLikes as $classLike) {
$shortClassLikeNames[] = $this->nodeNameResolver->getShortName($classLike);
}
return \array_unique($shortClassLikeNames);
}
/**
* @param Stmt[] $stmts
* @return array
*/
private function resolveForStmts(array $stmts) : array
{
$shortNamesToFullyQualifiedNames = [];
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $node) use(&$shortNamesToFullyQualifiedNames) {
// class name is used!
if ($node instanceof ClassLike && $node->name instanceof Identifier) {
$fullyQualifiedName = $this->nodeNameResolver->getName($node);
if ($fullyQualifiedName === null) {
return null;
}
$shortNamesToFullyQualifiedNames[$node->name->toString()] = $fullyQualifiedName;
return null;
}
if (!$node instanceof Name) {
return null;
}
$originalName = $node->getAttribute(AttributeKey::ORIGINAL_NAME);
if (!$originalName instanceof Name) {
return null;
}
// already short
if (\strpos($originalName->toString(), '\\') !== \false) {
return null;
}
$shortNamesToFullyQualifiedNames[$originalName->toString()] = $this->nodeNameResolver->getName($node);
return null;
});
$docBlockShortNamesToFullyQualifiedNames = $this->resolveFromStmtsDocBlocks($stmts);
/** @var array $result */
$result = \array_merge($shortNamesToFullyQualifiedNames, $docBlockShortNamesToFullyQualifiedNames);
return $result;
}
/**
* @param Stmt[] $stmts
* @return array
*/
private function resolveFromStmtsDocBlocks(array $stmts) : array
{
$shortNames = [];
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $node) use(&$shortNames) {
// speed up for nodes that are
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($node);
if (!$phpDocInfo instanceof PhpDocInfo) {
return null;
}
$phpDocNodeTraverser = new PhpDocNodeTraverser();
$phpDocNodeTraverser->traverseWithCallable($phpDocInfo->getPhpDocNode(), '', static function ($node) use(&$shortNames) {
if ($node instanceof PhpDocTagNode) {
$shortName = \trim($node->name, '@');
if (\ucfirst($shortName) === $shortName) {
$shortNames[] = $shortName;
}
return null;
}
if ($node instanceof IdentifierTypeNode) {
$shortNames[] = $node->name;
}
return null;
});
return null;
});
return $this->fqnizeShortNames($shortNames, $stmts);
}
/**
* @param string[] $shortNames
* @param Stmt[] $stmts
* @return array
*/
private function fqnizeShortNames(array $shortNames, array $stmts) : array
{
$shortNamesToFullyQualifiedNames = [];
foreach ($shortNames as $shortName) {
$stmtsMatchedName = $this->useImportNameMatcher->matchNameWithStmts($shortName, $stmts);
if ($stmtsMatchedName == null) {
continue;
}
$shortNamesToFullyQualifiedNames[$shortName] = $stmtsMatchedName;
}
return $shortNamesToFullyQualifiedNames;
}
}