1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-02 09:37:59 +01:00

Fix crashes when analysing aliased class instances

This commit is contained in:
Matthew Brown 2018-12-21 11:32:44 -05:00
parent e89425ad68
commit 947e3bf0f1
10 changed files with 49 additions and 24 deletions

View File

@ -194,11 +194,7 @@ class Codebase
$this->loadAnalyzer(); $this->loadAnalyzer();
$this->functions = new Internal\Codebase\Functions($providers->file_storage_provider, $this->reflection); $this->functions = new Internal\Codebase\Functions($providers->file_storage_provider, $this->reflection);
$this->methods = new Internal\Codebase\Methods(
$config,
$providers->classlike_storage_provider,
$providers->file_reference_provider
);
$this->properties = new Internal\Codebase\Properties( $this->properties = new Internal\Codebase\Properties(
$providers->classlike_storage_provider, $providers->classlike_storage_provider,
$providers->file_reference_provider $providers->file_reference_provider
@ -207,9 +203,16 @@ class Codebase
$this->classlikes = new Internal\Codebase\ClassLikes( $this->classlikes = new Internal\Codebase\ClassLikes(
$this->config, $this->config,
$providers->classlike_storage_provider, $providers->classlike_storage_provider,
$this->scanner, $this->scanner
$this->methods
); );
$this->methods = new Internal\Codebase\Methods(
$config,
$providers->classlike_storage_provider,
$providers->file_reference_provider,
$this->classlikes
);
$this->populator = new Internal\Codebase\Populator( $this->populator = new Internal\Codebase\Populator(
$config, $config,
$providers->classlike_storage_provider, $providers->classlike_storage_provider,

View File

@ -1026,6 +1026,8 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
$fq_class_name = strpos($method_id, '::') !== false ? explode('::', $method_id)[0] : null; $fq_class_name = strpos($method_id, '::') !== false ? explode('::', $method_id)[0] : null;
if ($fq_class_name) { if ($fq_class_name) {
$fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name);
if ($class_storage->user_defined || $class_storage->stubbed) { if ($class_storage->user_defined || $class_storage->stubbed) {

View File

@ -439,7 +439,7 @@ class ProjectAnalyzer
throw new \UnexpectedValueException('Should not be checking references'); throw new \UnexpectedValueException('Should not be checking references');
} }
$this->codebase->classlikes->checkClassReferences(); $this->codebase->classlikes->checkClassReferences($this->codebase->methods);
} }
/** /**

View File

@ -587,6 +587,8 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
self::collectSpecialInformation($source, $stmt->name->name, $context); self::collectSpecialInformation($source, $stmt->name->name, $context);
} }
$fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name);
if ($class_storage->template_types) { if ($class_storage->template_types) {

View File

@ -188,6 +188,8 @@ class CallAnalyzer
list($fq_class_name, $method_name) = explode('::', $method_id); list($fq_class_name, $method_name) = explode('::', $method_id);
$fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name);
$method_storage = null; $method_storage = null;

View File

@ -96,11 +96,6 @@ class ClassLikes
*/ */
private $config; private $config;
/**
* @var Methods
*/
private $methods;
/** /**
* @var Scanner * @var Scanner
*/ */
@ -112,13 +107,11 @@ class ClassLikes
public function __construct( public function __construct(
Config $config, Config $config,
ClassLikeStorageProvider $storage_provider, ClassLikeStorageProvider $storage_provider,
Scanner $scanner, Scanner $scanner
Methods $methods
) { ) {
$this->config = $config; $this->config = $config;
$this->classlike_storage_provider = $storage_provider; $this->classlike_storage_provider = $storage_provider;
$this->scanner = $scanner; $this->scanner = $scanner;
$this->methods = $methods;
$this->collectPredefinedClassLikes(); $this->collectPredefinedClassLikes();
} }
@ -657,7 +650,7 @@ class ClassLikes
/** /**
* @return void * @return void
*/ */
public function checkClassReferences() public function checkClassReferences(Methods $methods)
{ {
foreach ($this->existing_classlikes_lc as $fq_class_name_lc => $_) { foreach ($this->existing_classlikes_lc as $fq_class_name_lc => $_) {
try { try {
@ -680,7 +673,7 @@ class ClassLikes
// fall through // fall through
} }
} else { } else {
$this->checkMethodReferences($classlike_storage); $this->checkMethodReferences($classlike_storage, $methods);
} }
} }
} }
@ -748,7 +741,7 @@ class ClassLikes
/** /**
* @return void * @return void
*/ */
private function checkMethodReferences(ClassLikeStorage $classlike_storage) private function checkMethodReferences(ClassLikeStorage $classlike_storage, Methods $methods)
{ {
foreach ($classlike_storage->appearing_method_ids as $method_name => $appearing_method_id) { foreach ($classlike_storage->appearing_method_ids as $method_name => $appearing_method_id) {
list($appearing_fq_classlike_name) = explode('::', $appearing_method_id); list($appearing_fq_classlike_name) = explode('::', $appearing_method_id);
@ -789,7 +782,7 @@ class ClassLikes
if (isset($classlike_storage->overridden_method_ids[$method_name_lc])) { if (isset($classlike_storage->overridden_method_ids[$method_name_lc])) {
foreach ($classlike_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) { foreach ($classlike_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) {
$parent_method_storage = $this->methods->getStorage($parent_method_id); $parent_method_storage = $methods->getStorage($parent_method_id);
if (!$parent_method_storage->abstract || $parent_method_storage->referencing_locations) { if (!$parent_method_storage->abstract || $parent_method_storage->referencing_locations) {
$has_parent_references = true; $has_parent_references = true;
@ -842,7 +835,7 @@ class ClassLikes
if (isset($classlike_storage->overridden_method_ids[$method_name_lc])) { if (isset($classlike_storage->overridden_method_ids[$method_name_lc])) {
foreach ($classlike_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) { foreach ($classlike_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) {
$parent_method_storage = $this->methods->getStorage($parent_method_id); $parent_method_storage = $methods->getStorage($parent_method_id);
if (!$parent_method_storage->abstract if (!$parent_method_storage->abstract
&& isset($parent_method_storage->used_params[$offset]) && isset($parent_method_storage->used_params[$offset])

View File

@ -37,17 +37,24 @@ class Methods
*/ */
public $file_reference_provider; public $file_reference_provider;
/**
* @var ClassLikes
*/
private $classlikes;
/** /**
* @param ClassLikeStorageProvider $storage_provider * @param ClassLikeStorageProvider $storage_provider
*/ */
public function __construct( public function __construct(
\Psalm\Config $config, \Psalm\Config $config,
ClassLikeStorageProvider $storage_provider, ClassLikeStorageProvider $storage_provider,
FileReferenceProvider $file_reference_provider FileReferenceProvider $file_reference_provider,
ClassLikes $classlikes
) { ) {
$this->classlike_storage_provider = $storage_provider; $this->classlike_storage_provider = $storage_provider;
$this->config = $config; $this->config = $config;
$this->file_reference_provider = $file_reference_provider; $this->file_reference_provider = $file_reference_provider;
$this->classlikes = $classlikes;
} }
/** /**
@ -72,6 +79,8 @@ class Methods
$old_method_id = null; $old_method_id = null;
$fq_class_name = $this->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $this->classlike_storage_provider->get($fq_class_name); $class_storage = $this->classlike_storage_provider->get($fq_class_name);
if (isset($class_storage->declaring_method_ids[$method_name])) { if (isset($class_storage->declaring_method_ids[$method_name])) {
@ -271,6 +280,8 @@ class Methods
if ($this->config->use_phpdoc_method_without_magic_or_parent) { if ($this->config->use_phpdoc_method_without_magic_or_parent) {
list($original_fq_class_name, $original_method_name) = explode('::', $method_id); list($original_fq_class_name, $original_method_name) = explode('::', $method_id);
$original_fq_class_name = $this->classlikes->getUnAliasedName($original_fq_class_name);
$original_class_storage = $this->classlike_storage_provider->get($original_fq_class_name); $original_class_storage = $this->classlike_storage_provider->get($original_fq_class_name);
if (isset($original_class_storage->pseudo_methods[strtolower($original_method_name)])) { if (isset($original_class_storage->pseudo_methods[strtolower($original_method_name)])) {
@ -289,6 +300,8 @@ class Methods
if (!$checked_for_pseudo_method) { if (!$checked_for_pseudo_method) {
list($original_fq_class_name, $original_method_name) = explode('::', $method_id); list($original_fq_class_name, $original_method_name) = explode('::', $method_id);
$original_fq_class_name = $this->classlikes->getUnAliasedName($original_fq_class_name);
$original_class_storage = $this->classlike_storage_provider->get($original_fq_class_name); $original_class_storage = $this->classlike_storage_provider->get($original_fq_class_name);
if (isset($original_class_storage->pseudo_methods[strtolower($original_method_name)])) { if (isset($original_class_storage->pseudo_methods[strtolower($original_method_name)])) {
@ -301,6 +314,8 @@ class Methods
if (!$appearing_method_id) { if (!$appearing_method_id) {
list($fq_class_name, $method_name) = explode('::', $method_id); list($fq_class_name, $method_name) = explode('::', $method_id);
$fq_class_name = $this->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $this->classlike_storage_provider->get($fq_class_name); $class_storage = $this->classlike_storage_provider->get($fq_class_name);
if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) { if ($class_storage->abstract && isset($class_storage->overridden_method_ids[$method_name])) {
@ -485,6 +500,8 @@ class Methods
list($fq_class_name, $method_name) = explode('::', $method_id); list($fq_class_name, $method_name) = explode('::', $method_id);
$fq_class_name = $this->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $this->classlike_storage_provider->get($fq_class_name); $class_storage = $this->classlike_storage_provider->get($fq_class_name);
if (isset($class_storage->declaring_method_ids[$method_name])) { if (isset($class_storage->declaring_method_ids[$method_name])) {
@ -509,6 +526,8 @@ class Methods
list($fq_class_name, $method_name) = explode('::', $method_id); list($fq_class_name, $method_name) = explode('::', $method_id);
$fq_class_name = $this->classlikes->getUnAliasedName($fq_class_name);
$class_storage = $this->classlike_storage_provider->get($fq_class_name); $class_storage = $this->classlike_storage_provider->get($fq_class_name);
if (isset($class_storage->appearing_method_ids[$method_name])) { if (isset($class_storage->appearing_method_ids[$method_name])) {

View File

@ -504,6 +504,10 @@ class Scanner
$this->reflection->registerClass($reflected_class); $this->reflection->registerClass($reflected_class);
$this->reflected_classlikes_lc[$fq_classlike_name_lc] = true; $this->reflected_classlikes_lc[$fq_classlike_name_lc] = true;
} elseif ($this->fileExistsForClassLike($classlikes, $fq_classlike_name)) { } elseif ($this->fileExistsForClassLike($classlikes, $fq_classlike_name)) {
$fq_classlike_name_lc = strtolower($classlikes->getUnAliasedName(
$fq_classlike_name_lc
));
// even though we've checked this above, calling the method invalidates it // even though we've checked this above, calling the method invalidates it
if (isset($this->classlike_files[$fq_classlike_name_lc])) { if (isset($this->classlike_files[$fq_classlike_name_lc])) {
/** @var string */ /** @var string */

View File

@ -136,7 +136,7 @@ class DocumentationTest extends TestCase
$this->analyzeFile($file_path, $context); $this->analyzeFile($file_path, $context);
if ($check_references) { if ($check_references) {
$this->project_analyzer->getCodebase()->classlikes->checkClassReferences(); $this->project_analyzer->checkClassReferences();
} }
} }

View File

@ -88,7 +88,7 @@ echo $a;';
$file_contents $file_contents
); );
$this->project_analyzer->getCodebase()->classlikes->checkClassReferences(); $this->project_analyzer->checkClassReferences();
$this->analyzeFile('somefile.php', new Context()); $this->analyzeFile('somefile.php', new Context());