1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Fix #971 - be more robust in face of duplicate classes

This commit is contained in:
Matt Brown 2018-09-04 14:34:14 -04:00
parent 5d6fb4efdf
commit cbfebb7a69
6 changed files with 58 additions and 9 deletions

View File

@ -838,6 +838,8 @@ class ClassChecker extends ClassLikeChecker
$analyzed_method_id = $actual_method_id;
$classlike_storage_provider = $project_checker->classlike_storage_provider;
if ($class_context->self && $class_context->self !== $source->getFQCLN()) {
$analyzed_method_id = (string)$method_checker->getMethodId($class_context->self);
@ -853,7 +855,6 @@ class ClassChecker extends ClassLikeChecker
}
if ($declaring_method_id && $implementer_method_storage->abstract) {
$classlike_storage_provider = $project_checker->classlike_storage_provider;
$appearing_storage = $classlike_storage_provider->get($class_context->self);
$declaring_method_storage = $codebase->methods->getStorage($declaring_method_id);
@ -888,6 +889,12 @@ class ClassChecker extends ClassLikeChecker
$return_type_location = null;
$secondary_return_type_location = null;
$self_class = $classlike_storage_provider->get($class_context->self);
if ($self_class->has_visitor_issues) {
return;
}
$actual_method_storage = $codebase->methods->getStorage($actual_method_id);
if (!$actual_method_storage->has_template_return_type) {

View File

@ -155,6 +155,10 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
try {
$storage = $codebase->methods->getStorage($real_method_id);
} catch (\UnexpectedValueException $e) {
if ($class_storage->has_visitor_issues) {
return null;
}
if (!$class_storage->parent_classes) {
throw $e;
}

View File

@ -26,6 +26,10 @@ class InterfaceChecker extends ClassLikeChecker
throw new \LogicException('Something went badly wrong');
}
if (isset($class->isDuplicate)) {
return false;
}
if ($this->class->extends) {
foreach ($this->class->extends as $extended_interface) {
$extended_interface_name = self::getFQCLNFromNameObject(

View File

@ -298,6 +298,10 @@ class Populator
$parent_storage->invalid_dependencies
);
if ($parent_storage->has_visitor_issues) {
$storage->has_visitor_issues = true;
}
$storage->public_class_constants += $parent_storage->public_class_constants;
$storage->protected_class_constants += $parent_storage->protected_class_constants;

View File

@ -580,6 +580,8 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
$this->file_storage->has_visitor_issues = true;
}
$duplicate_storage->has_visitor_issues = true;
return false;
}
} elseif (!$duplicate_storage->location

View File

@ -14,8 +14,12 @@ class IncludeTest extends TestCase
*
* @return void
*/
public function testValidInclude(array $files, array $files_to_check, $hoist_constants = false)
{
public function testValidInclude(
array $files,
array $files_to_check,
$hoist_constants = false,
array $error_levels = []
) {
$codebase = $this->project_checker->getCodebase();
foreach ($files as $file_path => $contents) {
@ -27,9 +31,14 @@ class IncludeTest extends TestCase
$codebase->addFilesToAnalyze([$file_path => $file_path]);
}
$config = $codebase->config;
foreach ($error_levels as $error_level) {
$config->setCustomErrorLevel($error_level, \Psalm\Config::REPORT_SUPPRESS);
}
$codebase->scanFiles();
$config = $codebase->config;
$config->hoist_constants = $hoist_constants;
foreach ($files_to_check as $file_path) {
@ -51,8 +60,7 @@ class IncludeTest extends TestCase
public function testInvalidInclude(
array $files,
array $files_to_check,
$error_message,
$hoist_constants = false
$error_message
) {
$codebase = $this->project_checker->getCodebase();
@ -65,13 +73,12 @@ class IncludeTest extends TestCase
$codebase->addFilesToAnalyze([$file_path => $file_path]);
}
$codebase->scanFiles();
$config = $codebase->config;
$this->expectException('\Psalm\Exception\CodeException');
$this->expectExceptionMessageRegexp('/\b' . preg_quote($error_message, '/') . '\b/');
$config = $codebase->config;
$config->hoist_constants = $hoist_constants;
$codebase->scanFiles();
foreach ($files_to_check as $file_path) {
$file_checker = new FileChecker($this->project_checker, $file_path, $config->shortenFileName($file_path));
@ -433,9 +440,30 @@ class IncludeTest extends TestCase
],
'files_to_check' => [
getcwd() . DIRECTORY_SEPARATOR . 'file1.php',
getcwd() . DIRECTORY_SEPARATOR . 'file2.php',
],
'hoist_constants' => true,
],
'duplicateClasses' => [
'files' => [
getcwd() . DIRECTORY_SEPARATOR . 'file1.php' => '<?php
class A {
public function aa() : void {}
public function bb() : void { $this->aa(); }
}',
getcwd() . DIRECTORY_SEPARATOR . 'file2.php' => '<?php
class A {
public function dd() : void {}
public function zz() : void { $this->dd(); }
}',
],
'files_to_check' => [
getcwd() . DIRECTORY_SEPARATOR . 'file1.php',
getcwd() . DIRECTORY_SEPARATOR . 'file2.php',
],
'hoist_constants' => false,
'error_levels' => ['DuplicateClass'],
],
];
}