phpstorm-stubs/tests/Parsers/StubParser.php

95 lines
3.6 KiB
PHP

<?php
declare(strict_types=1);
namespace StubTests\Parsers;
use FilesystemIterator;
use LogicException;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\NodeVisitorAbstract;
use PhpParser\ParserFactory;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
use StubTests\Model\StubsContainer;
use StubTests\Parsers\Visitors\ASTVisitor;
use StubTests\Parsers\Visitors\CoreStubASTVisitor;
use StubTests\Parsers\Visitors\ParentConnector;
use StubTests\TestData\Providers\PhpCoreStubsProvider;
use UnexpectedValueException;
class StubParser
{
private static ?StubsContainer $stubs = null;
public static function getPhpStormStubs(): StubsContainer
{
self::$stubs = new StubsContainer();
$visitor = new ASTVisitor(self::$stubs);
$coreStubVisitor = new CoreStubASTVisitor(self::$stubs);
/** @noinspection PhpUnhandledExceptionInspection */
self::processStubs($visitor, $coreStubVisitor, function ($file) {
return $file->getFilename() !== '.phpstorm.meta.php';
});
foreach (self::$stubs->getInterfaces() as $interface) {
$interface->parentInterfaces = $visitor->combineParentInterfaces($interface);
}
foreach (self::$stubs->getClasses() as $class) {
$class->interfaces =
Utils::flattenArray($visitor->combineImplementedInterfaces($class), false);
}
return self::$stubs;
}
/**
* @param NodeVisitorAbstract $visitor
* @param CoreStubASTVisitor|null $coreStubASTVisitor
* @param callable $fileCondition
* @throws LogicException
* @throws UnexpectedValueException
*/
public static function processStubs(NodeVisitorAbstract $visitor, ?CoreStubASTVisitor $coreStubASTVisitor, callable $fileCondition): void
{
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$nameResolver = new NameResolver(null, ['preserveOriginalNames' => true]);
$stubsIterator =
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(__DIR__ . '/../../', FilesystemIterator::SKIP_DOTS)
);
$coreStubDirectories = PhpCoreStubsProvider::getCoreStubsDirectories();
/** @var SplFileInfo $file */
foreach ($stubsIterator as $file) {
if (!$fileCondition($file) || basename(dirname($file->getRealPath())) === 'phpstorm-stubs' ||
strpos($file->getRealPath(), 'vendor') || strpos($file->getRealPath(), '.git') ||
strpos($file->getRealPath(), 'tests') || strpos($file->getRealPath(), '.idea')) {
continue;
}
$code = file_get_contents($file->getRealPath());
$traverser = new NodeTraverser();
$traverser->addVisitor(new ParentConnector());
$traverser->addVisitor($nameResolver);
if ($coreStubASTVisitor !== null && self::stubBelongsToCore($file, $coreStubDirectories)){
$traverser->addVisitor($coreStubASTVisitor);
}else {
$traverser->addVisitor($visitor);
}
$traverser->traverse($parser->parse($code, new StubsParserErrorHandler()));
}
}
private static function stubBelongsToCore(SplFileInfo $file, array $coreStubDirectories): bool
{
$filePath = dirname($file->getRealPath());
while (stripos($filePath, 'phpstorm-stubs') !== strlen($filePath) - strlen('phpstorm-stubs')){
if (in_array(basename($filePath), $coreStubDirectories, true)){
return true;
}
$filePath = dirname($filePath);
}
return false;
}
}