1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Use composer autoloader for class resolution where possible

This commit is contained in:
Matthew Brown 2018-03-03 15:19:05 -05:00
parent 1982d08573
commit ade9e03c85
4 changed files with 47 additions and 83 deletions

View File

@ -377,23 +377,19 @@ class Scanner
throw new \InvalidArgumentException('Why are you asking about a builtin class?');
}
if ($this->composer_classmap === null) {
$this->composer_classmap = $this->config->getComposerClassMap($this->debug_output);
}
$composer_file_path = $this->config->getComposerFilePathForClassLike($fq_class_name);
if (isset($this->composer_classmap[$fq_class_name_lc])) {
if (file_exists($this->composer_classmap[$fq_class_name_lc])) {
if ($this->debug_output) {
echo 'Using generated composer classmap to locate file for ' . $fq_class_name . PHP_EOL;
}
$classlikes->addFullyQualifiedClassLikeName(
$fq_class_name_lc,
$this->composer_classmap[$fq_class_name_lc]
);
return true;
if ($composer_file_path && file_exists($composer_file_path)) {
if ($this->debug_output) {
echo 'Using composer to locate file for ' . $fq_class_name . PHP_EOL;
}
$classlikes->addFullyQualifiedClassLikeName(
$fq_class_name_lc,
realpath($composer_file_path)
);
return true;
}
$old_level = error_reporting();

View File

@ -1,6 +1,7 @@
<?php
namespace Psalm;
use Composer\Autoload\ClassLoader;
use Psalm\Checker\ClassLikeChecker;
use Psalm\Checker\ProjectChecker;
use Psalm\Config\IssueHandler;
@ -233,6 +234,9 @@ class Config
/** @var array<string, bool> */
private $predefined_functions = [];
/** @var ClassLoader|null */
private $composer_class_loader;
protected function __construct()
{
self::$instance = $this;
@ -512,6 +516,11 @@ class Config
throw new \UnexpectedValueException('No config initialized');
}
public function setComposerClassLoader(ClassLoader $loader)
{
$this->composer_class_loader = $loader;
}
/**
* @param string $issue_key
* @param string $error_level
@ -941,74 +950,17 @@ class Config
}
/**
* @param bool $debug_output
* @return array<string, string>
* @param string $fq_classlike_name
*
* @psalm-suppress LessSpecificReturnStatement
* @psalm-suppress MoreSpecificReturnType
* @return string|false
*/
public function getComposerClassMap($debug_output)
public function getComposerFilePathForClassLike($fq_classlike_name)
{
if ($debug_output) {
echo 'Trying to get composer classmap in ' . $this->base_dir . PHP_EOL;
if (!$this->composer_class_loader) {
throw new \LogicException('Composer class loader should exist here');
}
$vendor_dir_path = $this->base_dir . self::getVendorDir($this->base_dir);
if (!is_dir($vendor_dir_path)) {
if ($debug_output) {
echo 'Could not resolve path to ' . $vendor_dir_path . PHP_EOL;
}
return [];
}
$vendor_dir_path = realpath($vendor_dir_path);
if (!$vendor_dir_path) {
if ($debug_output) {
echo 'Realpath failed when loading composer classmap' . PHP_EOL;
}
return [];
}
$autoload_files_classmap =
$vendor_dir_path . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR . 'autoload_classmap.php';
if (!file_exists($autoload_files_classmap)) {
if ($debug_output) {
echo 'No autoload_classmap.php found in ' . $vendor_dir_path . PHP_EOL;
}
return [];
}
/**
* @psalm-suppress MixedAssignment
* @psalm-suppress UnresolvableInclude
*/
$class_map = include_once $autoload_files_classmap;
if (is_array($class_map)) {
$composer_classmap = array_change_key_case($class_map);
$composer_classmap = array_filter(
$composer_classmap,
/**
* @param string $file_path
*
* @return bool
*/
function ($file_path) use ($vendor_dir_path) {
return strpos($file_path, $vendor_dir_path) === 0;
}
);
} else {
$composer_classmap = [];
}
return $composer_classmap;
return $this->composer_class_loader->findFile($fq_classlike_name);
}
/**

View File

@ -5,7 +5,7 @@
* @param bool $has_explicit_root
* @param string $vendor_dir
*
* @return void
* @return \Composer\Autoload\ClassLoader
*/
function requireAutoloaders($current_dir, $has_explicit_root, $vendor_dir)
{
@ -25,7 +25,10 @@ function requireAutoloaders($current_dir, $has_explicit_root, $vendor_dir)
$nested_autoload_file = dirname(dirname($autoload_root)) . DIRECTORY_SEPARATOR . 'autoload.php';
if (file_exists($nested_autoload_file)) {
$autoload_files[] = realpath($nested_autoload_file);
$nested_autoload_file_path = realpath($nested_autoload_file);
if (!in_array($nested_autoload_file_path, $autoload_files, false)) {
$autoload_files[] = $nested_autoload_file_path;
}
$has_autoloader = true;
}
@ -33,7 +36,10 @@ function requireAutoloaders($current_dir, $has_explicit_root, $vendor_dir)
$autoload_root . DIRECTORY_SEPARATOR . $vendor_dir . DIRECTORY_SEPARATOR . 'autoload.php';
if (file_exists($vendor_autoload_file)) {
$autoload_files[] = realpath($vendor_autoload_file);
$autoload_file_path = realpath($vendor_autoload_file);
if (!in_array($autoload_file_path, $autoload_files, false)) {
$autoload_files[] = $autoload_file_path;
}
$has_autoloader = true;
}
@ -49,12 +55,20 @@ function requireAutoloaders($current_dir, $has_explicit_root, $vendor_dir)
}
}
$first_autoloader = null;
foreach ($autoload_files as $file) {
/** @psalm-suppress UnresolvableInclude */
require_once $file;
$autoloader = require_once $file;
if (!$first_autoloader) {
$first_autoloader = $autoloader;
}
}
define('PSALM_VERSION', (string) \Muglug\PackageVersions\Versions::getVersion('vimeo/psalm'));
return $first_autoloader;
}
/**

View File

@ -139,7 +139,7 @@ if (isset($options['r']) && is_string($options['r'])) {
$vendor_dir = getVendorDir($current_dir);
requireAutoloaders($current_dir, isset($options['r']), $vendor_dir);
$first_autoloader = requireAutoloaders($current_dir, isset($options['r']), $vendor_dir);
if (array_key_exists('v', $options)) {
echo 'Psalm ' . PSALM_VERSION . PHP_EOL;
@ -266,6 +266,8 @@ if ($path_to_config) {
$config = Config::getConfigForPath($current_dir, $current_dir, $output_format);
}
$config->setComposerClassLoader($first_autoloader);
$file_storage_cache_provider = isset($options['no-cache'])
? new Psalm\Provider\NoCache\NoFileStorageCacheProvider()
: new Psalm\Provider\FileStorageCacheProvider($config);