1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-15 02:47:02 +01:00
psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php

668 lines
20 KiB
PHP
Raw Normal View History

2016-01-08 00:28:27 +01:00
<?php
2018-11-06 03:57:36 +01:00
namespace Psalm\Internal\Analyzer;
2016-01-08 00:28:27 +01:00
2016-11-02 07:29:00 +01:00
use PhpParser;
2018-11-06 03:57:36 +01:00
use Psalm\Codebase;
use Psalm\CodeLocation\DocblockTypeLocation;
use Psalm\Context;
use Psalm\Exception\UnpreparedAnalysisException;
use Psalm\Internal\FileManipulation\FileManipulationBuffer;
use Psalm\Internal\Type\TypeAlias\LinkableTypeAlias;
use Psalm\Issue\InvalidTypeImport;
use Psalm\Issue\UncaughtThrowInGlobalScope;
use Psalm\IssueBuffer;
use Psalm\Plugin\EventHandler\Event\AfterFileAnalysisEvent;
use Psalm\Plugin\EventHandler\Event\BeforeFileAnalysisEvent;
use Psalm\Type;
use function implode;
use function strtolower;
use function strpos;
use function array_keys;
use function count;
/**
* @internal
* @psalm-consistent-constructor
*/
class FileAnalyzer extends SourceAnalyzer
2016-01-08 00:28:27 +01:00
{
2017-01-07 20:35:07 +01:00
use CanAlias;
/**
* @var string
*/
protected $file_name;
2016-10-14 06:53:43 +02:00
/**
* @var string
*/
protected $file_path;
2016-10-14 06:53:43 +02:00
2017-01-07 20:35:07 +01:00
/**
* @var string|null
*/
protected $root_file_path;
/**
* @var string|null
2017-01-07 20:35:07 +01:00
*/
protected $root_file_name;
2017-01-07 20:35:07 +01:00
/**
* @var array<string, bool>
2017-01-07 20:35:07 +01:00
*/
private $required_file_paths = [];
2017-01-07 20:35:07 +01:00
/**
* @var array<string, bool>
*/
private $parent_file_paths = [];
2017-01-07 20:35:07 +01:00
/**
* @var array<string>
2017-01-07 20:35:07 +01:00
*/
private $suppressed_issues = [];
2017-01-07 20:35:07 +01:00
2016-11-13 00:51:48 +01:00
/**
* @var array<string, array<string, string>>
2016-10-31 20:42:20 +01:00
*/
private $namespace_aliased_classes = [];
2016-11-13 00:51:48 +01:00
/**
* @var array<string, array<lowercase-string, string>>
2016-11-13 00:51:48 +01:00
*/
private $namespace_aliased_classes_flipped = [];
2016-11-13 00:51:48 +01:00
2019-06-06 04:13:33 +02:00
/**
* @var array<string, array<string, string>>
*/
private $namespace_aliased_classes_flipped_replaceable = [];
/**
* @var array<lowercase-string, InterfaceAnalyzer>
*/
public $interface_analyzers_to_analyze = [];
/**
* @var array<lowercase-string, ClassAnalyzer>
*/
public $class_analyzers_to_analyze = [];
/**
* @var null|Context
*/
2017-01-12 06:54:41 +01:00
public $context;
/**
2018-11-06 03:57:36 +01:00
* @var ProjectAnalyzer
*/
2018-11-11 18:01:14 +01:00
public $project_analyzer;
2018-11-06 03:57:36 +01:00
/**
* @var Codebase
*/
public $codebase;
2019-06-05 17:15:52 +02:00
/**
* @var int
*/
private $first_statement_offset = -1;
/** @var ?\Psalm\Internal\Provider\NodeDataProvider */
private $node_data;
2020-06-13 21:48:12 +02:00
/** @var ?Type\Union */
private $return_type;
public function __construct(ProjectAnalyzer $project_analyzer, string $file_path, string $file_name)
2018-01-21 18:44:46 +01:00
{
2018-11-06 03:57:36 +01:00
$this->source = $this;
$this->file_path = $file_path;
2018-01-21 18:44:46 +01:00
$this->file_name = $file_name;
2018-11-11 18:01:14 +01:00
$this->project_analyzer = $project_analyzer;
$this->codebase = $project_analyzer->getCodebase();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
public function analyze(
?Context $file_context = null,
?Context $global_context = null
): void {
2018-11-11 18:01:14 +01:00
$codebase = $this->project_analyzer->getCodebase();
$file_storage = $codebase->file_storage_provider->get($this->file_path);
if (!$file_storage->deep_scan && !$codebase->server_mode) {
throw new UnpreparedAnalysisException('File ' . $this->file_path . ' has not been properly scanned');
}
if ($file_storage->has_visitor_issues) {
return;
}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
if ($file_context) {
$this->context = $file_context;
}
2017-02-01 01:21:33 +01:00
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
if (!$this->context) {
$this->context = new Context();
}
2016-11-02 07:29:00 +01:00
if ($codebase->config->useStrictTypesForFile($this->file_path)) {
$this->context->strict_types = true;
}
$this->context->is_global = true;
2019-03-11 14:54:41 +01:00
$this->context->defineGlobals();
$this->context->collect_exceptions = $codebase->config->check_for_throws_in_global_scope;
try {
$stmts = $codebase->getStatementsForFile($this->file_path);
} catch (PhpParser\Error $e) {
return;
}
$event = new BeforeFileAnalysisEvent($this, $this->context, $file_storage, $codebase);
$codebase->config->eventDispatcher->dispatchBeforeFileAnalysis($event);
2016-11-02 07:29:00 +01:00
2019-06-05 17:15:52 +02:00
if ($codebase->alter_code) {
foreach ($stmts as $stmt) {
if (!$stmt instanceof PhpParser\Node\Stmt\Declare_) {
$this->first_statement_offset = (int) $stmt->getAttribute('startFilePos');
break;
}
}
}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$leftover_stmts = $this->populateCheckers($stmts);
$this->node_data = new \Psalm\Internal\Provider\NodeDataProvider();
$statements_analyzer = new StatementsAnalyzer($this, $this->node_data);
foreach ($file_storage->docblock_issues as $docblock_issue) {
IssueBuffer::add($docblock_issue);
}
// if there are any leftover statements, evaluate them,
// in turn causing the classes/interfaces be evaluated
if ($leftover_stmts) {
2018-11-11 18:01:14 +01:00
$statements_analyzer->analyze($leftover_stmts, $this->context, $global_context, true);
2020-06-13 21:48:12 +02:00
foreach ($leftover_stmts as $leftover_stmt) {
if ($leftover_stmt instanceof PhpParser\Node\Stmt\Return_) {
if ($leftover_stmt->expr) {
2020-06-13 22:45:54 +02:00
$this->return_type = $statements_analyzer->node_data->getType($leftover_stmt->expr)
?: Type::getMixed();
2020-06-13 21:48:12 +02:00
} else {
$this->return_type = Type::getVoid();
}
break;
}
}
}
// check any leftover interfaces not already evaluated
2018-11-11 18:01:14 +01:00
foreach ($this->interface_analyzers_to_analyze as $interface_analyzer) {
$interface_analyzer->analyze();
}
// check any leftover classes not already evaluated
2018-11-11 18:01:14 +01:00
foreach ($this->class_analyzers_to_analyze as $class_analyzer) {
$class_analyzer->analyze(null, $this->context);
2016-08-05 21:11:20 +02:00
}
if ($codebase->config->check_for_throws_in_global_scope) {
$uncaught_throws = $statements_analyzer->getUncaughtThrows($this->context);
foreach ($uncaught_throws as $possibly_thrown_exception => $codelocations) {
foreach ($codelocations as $codelocation) {
// issues are suppressed in ThrowAnalyzer, CallAnalyzer, etc.
if (IssueBuffer::accepts(
new UncaughtThrowInGlobalScope(
$possibly_thrown_exception . ' is thrown but not caught in global scope',
$codelocation
)
)) {
// fall through
}
}
}
}
// validate type imports
if ($file_storage->type_aliases) {
foreach ($file_storage->type_aliases as $alias) {
if ($alias instanceof LinkableTypeAlias) {
$location = new DocblockTypeLocation(
$this->getSource(),
$alias->start_offset,
$alias->end_offset,
$alias->line_number
);
$fq_source_classlike = $alias->declaring_fq_classlike_name;
if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
$this->getSource(),
$fq_source_classlike,
$location,
null,
null,
$this->suppressed_issues,
new ClassLikeNameOptions(
true,
false,
true,
true,
true
)
) === false) {
continue;
}
$referenced_class_storage = $codebase->classlike_storage_provider->get($fq_source_classlike);
if (!isset($referenced_class_storage->type_aliases[$alias->alias_name])) {
IssueBuffer::accepts(
new InvalidTypeImport(
'Type alias ' . $alias->alias_name
. ' imported from ' . $fq_source_classlike
. ' is not defined on the source class',
$location
)
);
}
}
}
}
$event = new AfterFileAnalysisEvent($this, $this->context, $file_storage, $codebase, $stmts);
$codebase->config->eventDispatcher->dispatchAfterFileAnalysis($event);
$this->class_analyzers_to_analyze = [];
$this->interface_analyzers_to_analyze = [];
2016-01-08 00:28:27 +01:00
}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
/**
* @param array<int, PhpParser\Node\Stmt> $stmts
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
*
2020-10-17 18:36:44 +02:00
* @return list<PhpParser\Node\Stmt>
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
*/
public function populateCheckers(array $stmts): array
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
{
$leftover_stmts = [];
foreach ($stmts as $stmt) {
if ($stmt instanceof PhpParser\Node\Stmt\ClassLike) {
2018-11-06 03:57:36 +01:00
$this->populateClassLikeAnalyzers($stmt);
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Namespace_) {
$namespace_name = $stmt->name ? implode('\\', $stmt->name->parts) : '';
2018-11-11 18:01:14 +01:00
$namespace_analyzer = new NamespaceAnalyzer($stmt, $this);
$namespace_analyzer->collectAnalyzableInformation();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
2018-11-11 18:01:14 +01:00
$this->namespace_aliased_classes[$namespace_name] = $namespace_analyzer->getAliases()->uses;
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->namespace_aliased_classes_flipped[$namespace_name] =
2018-11-11 18:01:14 +01:00
$namespace_analyzer->getAliasedClassesFlipped();
2019-06-06 04:13:33 +02:00
$this->namespace_aliased_classes_flipped_replaceable[$namespace_name] =
$namespace_analyzer->getAliasedClassesFlippedReplaceable();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Use_) {
$this->visitUse($stmt);
} elseif ($stmt instanceof PhpParser\Node\Stmt\GroupUse) {
$this->visitGroupUse($stmt);
} else {
if ($stmt instanceof PhpParser\Node\Stmt\If_) {
foreach ($stmt->stmts as $if_stmt) {
if ($if_stmt instanceof PhpParser\Node\Stmt\ClassLike) {
2018-11-06 03:57:36 +01:00
$this->populateClassLikeAnalyzers($if_stmt);
}
}
}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$leftover_stmts[] = $stmt;
}
}
return $leftover_stmts;
}
private function populateClassLikeAnalyzers(PhpParser\Node\Stmt\ClassLike $stmt): void
{
if ($stmt instanceof PhpParser\Node\Stmt\Class_ || $stmt instanceof PhpParser\Node\Stmt\Enum_) {
2020-08-03 08:20:58 +02:00
if (!$stmt->name) {
return;
}
// this can happen when stubbing
if (!$this->codebase->classExists($stmt->name->name)
&& !$this->codebase->classlikes->enumExists($stmt->name->name)
) {
2020-08-03 08:20:58 +02:00
return;
}
2018-11-11 18:01:14 +01:00
$class_analyzer = new ClassAnalyzer($stmt, $this, $stmt->name->name);
2018-11-11 18:01:14 +01:00
$fq_class_name = $class_analyzer->getFQCLN();
2018-11-11 18:01:14 +01:00
$this->class_analyzers_to_analyze[strtolower($fq_class_name)] = $class_analyzer;
} elseif ($stmt instanceof PhpParser\Node\Stmt\Interface_) {
2020-08-03 08:20:58 +02:00
if (!$stmt->name) {
return;
}
// this can happen when stubbing
if (!$this->codebase->interfaceExists($stmt->name->name)) {
return;
}
2018-11-11 18:01:14 +01:00
$class_analyzer = new InterfaceAnalyzer($stmt, $this, $stmt->name->name);
2018-11-11 18:01:14 +01:00
$fq_class_name = $class_analyzer->getFQCLN();
$this->interface_analyzers_to_analyze[strtolower($fq_class_name)] = $class_analyzer;
}
}
public function addNamespacedClassAnalyzer(string $fq_class_name, ClassAnalyzer $class_analyzer): void
{
2018-11-11 18:01:14 +01:00
$this->class_analyzers_to_analyze[strtolower($fq_class_name)] = $class_analyzer;
}
public function addNamespacedInterfaceAnalyzer(string $fq_class_name, InterfaceAnalyzer $interface_analyzer): void
{
2018-11-11 18:01:14 +01:00
$this->interface_analyzers_to_analyze[strtolower($fq_class_name)] = $interface_analyzer;
}
public function getMethodMutations(
\Psalm\Internal\MethodIdentifier $method_id,
Context $this_context,
bool $from_project_analyzer = false
): void {
$fq_class_name = $method_id->fq_class_name;
$method_name = $method_id->method_name;
$fq_class_name_lc = strtolower($fq_class_name);
if (isset($this->class_analyzers_to_analyze[$fq_class_name_lc])) {
$class_analyzer_to_examine = $this->class_analyzers_to_analyze[$fq_class_name_lc];
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
} else {
if (!$from_project_analyzer) {
$this->project_analyzer->getMethodMutations(
$method_id,
$this_context,
$this->getRootFilePath(),
$this->getRootFileName()
);
}
return;
}
$call_context = new Context($this_context->self);
$call_context->collect_mutations = $this_context->collect_mutations;
2018-01-24 19:38:53 +01:00
$call_context->collect_initializations = $this_context->collect_initializations;
$call_context->collect_nonprivate_initializations = $this_context->collect_nonprivate_initializations;
2018-01-24 19:38:53 +01:00
$call_context->initialized_methods = $this_context->initialized_methods;
$call_context->include_location = $this_context->include_location;
$call_context->calling_method_id = $this_context->calling_method_id;
2017-01-12 03:37:53 +01:00
foreach ($this_context->vars_possibly_in_scope as $var => $_) {
2017-01-12 03:37:53 +01:00
if (strpos($var, '$this->') === 0) {
$call_context->vars_possibly_in_scope[$var] = true;
}
}
foreach ($this_context->vars_in_scope as $var => $type) {
if (strpos($var, '$this->') === 0) {
$call_context->vars_in_scope[$var] = $type;
}
}
if (!isset($this_context->vars_in_scope['$this'])) {
throw new \UnexpectedValueException('Should exist');
}
2017-01-12 03:37:53 +01:00
$call_context->vars_in_scope['$this'] = $this_context->vars_in_scope['$this'];
2018-11-11 18:01:14 +01:00
$class_analyzer_to_examine->getMethodMutations($method_name, $call_context);
2017-01-12 06:54:41 +01:00
2017-01-19 05:19:36 +01:00
foreach ($call_context->vars_possibly_in_scope as $var => $_) {
2017-01-12 03:37:53 +01:00
$this_context->vars_possibly_in_scope[$var] = true;
}
foreach ($call_context->vars_in_scope as $var => $type) {
$this_context->vars_in_scope[$var] = $type;
}
}
2020-10-17 18:36:44 +02:00
public function getFunctionLikeAnalyzer(\Psalm\Internal\MethodIdentifier $method_id) : ?MethodAnalyzer
{
$fq_class_name = $method_id->fq_class_name;
$method_name = $method_id->method_name;
$fq_class_name_lc = strtolower($fq_class_name);
if (!isset($this->class_analyzers_to_analyze[$fq_class_name_lc])) {
return null;
}
$class_analyzer_to_examine = $this->class_analyzers_to_analyze[$fq_class_name_lc];
return $class_analyzer_to_examine->getFunctionLikeAnalyzer($method_name);
}
public function getNamespace(): ?string
{
return null;
}
2016-11-13 00:51:48 +01:00
/**
* @return array<lowercase-string, string>
2016-11-13 00:51:48 +01:00
*/
public function getAliasedClassesFlipped(?string $namespace_name = null): array
2016-11-13 00:51:48 +01:00
{
if ($namespace_name && isset($this->namespace_aliased_classes_flipped[$namespace_name])) {
return $this->namespace_aliased_classes_flipped[$namespace_name];
}
return $this->aliased_classes_flipped;
}
2019-06-06 04:13:33 +02:00
/**
* @return array<string, string>
*/
public function getAliasedClassesFlippedReplaceable(?string $namespace_name = null): array
2019-06-06 04:13:33 +02:00
{
if ($namespace_name && isset($this->namespace_aliased_classes_flipped_replaceable[$namespace_name])) {
return $this->namespace_aliased_classes_flipped_replaceable[$namespace_name];
}
return $this->aliased_classes_flipped_replaceable;
}
public static function clearCache(): void
2016-03-23 18:05:25 +01:00
{
\Psalm\Internal\Type\TypeTokenizer::clearCache();
2019-05-17 00:36:36 +02:00
\Psalm\Internal\Codebase\Reflection::clearCache();
\Psalm\Internal\Codebase\Functions::clearCache();
IssueBuffer::clearCache();
FileManipulationBuffer::clearCache();
2018-11-06 03:57:36 +01:00
FunctionLikeAnalyzer::clearCache();
\Psalm\Internal\Provider\ClassLikeStorageProvider::deleteAll();
\Psalm\Internal\Provider\FileStorageProvider::deleteAll();
\Psalm\Internal\Provider\FileReferenceProvider::clearCache();
\Psalm\Internal\Codebase\InternalCallMapHandler::clearCache();
}
public function getFileName(): string
2017-01-07 20:35:07 +01:00
{
return $this->file_name;
}
public function getFilePath(): string
2017-01-07 20:35:07 +01:00
{
return $this->file_path;
}
public function getRootFileName(): string
2017-01-07 20:35:07 +01:00
{
return $this->root_file_name ?: $this->file_name;
2017-01-07 20:35:07 +01:00
}
public function getRootFilePath(): string
2017-01-07 20:35:07 +01:00
{
return $this->root_file_path ?: $this->file_path;
}
public function setRootFilePath(string $file_path, string $file_name): void
{
$this->root_file_name = $file_name;
$this->root_file_path = $file_path;
}
public function addRequiredFilePath(string $file_path): void
{
$this->required_file_paths[$file_path] = true;
}
public function addParentFilePath(string $file_path): void
{
$this->parent_file_paths[$file_path] = true;
}
public function hasParentFilePath(string $file_path): bool
{
return $this->file_path === $file_path || isset($this->parent_file_paths[$file_path]);
}
public function hasAlreadyRequiredFilePath(string $file_path): bool
{
return isset($this->required_file_paths[$file_path]);
}
/**
2020-10-17 18:36:44 +02:00
* @return list<string>
*/
public function getRequiredFilePaths(): array
{
return array_keys($this->required_file_paths);
}
/**
2020-10-17 18:36:44 +02:00
* @return list<string>
*/
public function getParentFilePaths(): array
{
return array_keys($this->parent_file_paths);
}
public function getRequireNesting(): int
{
return count($this->parent_file_paths);
2017-01-07 20:35:07 +01:00
}
/**
* @return array<string>
*/
public function getSuppressedIssues(): array
2017-01-07 20:35:07 +01:00
{
return $this->suppressed_issues;
}
/**
* @param array<int, string> $new_issues
*/
public function addSuppressedIssues(array $new_issues): void
{
if (isset($new_issues[0])) {
$new_issues = \array_combine($new_issues, $new_issues);
}
$this->suppressed_issues = $new_issues + $this->suppressed_issues;
}
/**
* @param array<int, string> $new_issues
*/
public function removeSuppressedIssues(array $new_issues): void
{
if (isset($new_issues[0])) {
$new_issues = \array_combine($new_issues, $new_issues);
}
$this->suppressed_issues = \array_diff_key($this->suppressed_issues, $new_issues);
}
public function getFQCLN(): ?string
2017-01-07 20:35:07 +01:00
{
return null;
}
public function getParentFQCLN(): ?string
{
return null;
}
public function getClassName(): ?string
2017-01-09 06:26:40 +01:00
{
return null;
}
/**
* @return array<string, array<string, Type\Union>>|null
*/
public function getTemplateTypeMap(): ?array
{
return null;
}
public function isStatic(): bool
2017-01-07 20:35:07 +01:00
{
return false;
}
/**
* @psalm-mutation-free
*/
2018-11-06 03:57:36 +01:00
public function getFileAnalyzer() : FileAnalyzer
{
return $this;
}
2018-11-06 03:57:36 +01:00
2020-08-28 18:48:33 +02:00
/**
* @psalm-mutation-free
*/
2018-11-06 03:57:36 +01:00
public function getProjectAnalyzer() : ProjectAnalyzer
{
2018-11-11 18:01:14 +01:00
return $this->project_analyzer;
2018-11-06 03:57:36 +01:00
}
public function getCodebase() : Codebase
{
return $this->codebase;
}
2019-06-05 17:15:52 +02:00
public function getFirstStatementOffset() : int
{
return $this->first_statement_offset;
}
2019-06-30 03:06:21 +02:00
public function getNodeTypeProvider() : \Psalm\NodeTypeProvider
{
if (!$this->node_data) {
throw new \UnexpectedValueException('There should be a node type provider');
}
return $this->node_data;
}
2020-06-13 21:48:12 +02:00
public function getReturnType() : ?Type\Union
{
return $this->return_type;
}
2019-06-30 03:13:02 +02:00
public function clearSourceBeforeDestruction() : void
2019-06-30 03:06:21 +02:00
{
2019-06-30 03:13:02 +02:00
/** @psalm-suppress PossiblyNullPropertyAssignmentValue */
2019-06-30 03:06:21 +02:00
$this->source = null;
}
2016-01-08 00:28:27 +01:00
}