1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Fix #510 - check that constructor parent classes and interfaces exist

This commit is contained in:
Matt Brown 2018-02-14 11:21:43 -05:00
parent d0a2258806
commit be75c143d4
3 changed files with 51 additions and 12 deletions

View File

@ -76,6 +76,8 @@ class ClassChecker extends ClassLikeChecker
$fq_class_name = $class_context && $class_context->self ? $class_context->self : $this->fq_class_name;
$storage = $this->storage;
if (preg_match(
'/(^|\\\)(int|float|bool|string|void|null|false|true|resource|object|numeric|mixed)$/i',
$fq_class_name
@ -94,7 +96,7 @@ class ClassChecker extends ClassLikeChecker
true
)
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->source->getSuppressedIssues())
)) {
// fall through
}
@ -102,8 +104,6 @@ class ClassChecker extends ClassLikeChecker
return null;
}
$storage = $this->storage;
$project_checker = $this->file_checker->project_checker;
$codebase = $project_checker->codebase;
@ -120,7 +120,7 @@ class ClassChecker extends ClassLikeChecker
$this,
$this->parent_fq_class_name,
$parent_reference_location,
$this->getSuppressedIssues(),
array_merge($storage->suppressed_issues, $this->getSuppressedIssues()),
false
) === false) {
return false;
@ -142,7 +142,7 @@ class ClassChecker extends ClassLikeChecker
$this->parent_fq_class_name . ' is marked deprecated',
$code_location
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
// fall through
}
@ -196,7 +196,7 @@ class ClassChecker extends ClassLikeChecker
$interface_name . ' is marked deprecated',
$code_location
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
// fall through
}
@ -229,7 +229,7 @@ class ClassChecker extends ClassLikeChecker
$storage->name,
$code_location
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
return false;
}
@ -244,7 +244,7 @@ class ClassChecker extends ClassLikeChecker
. ' must be public in ' . $storage->name,
$code_location
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
return false;
}
@ -294,7 +294,7 @@ class ClassChecker extends ClassLikeChecker
true
)
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
return false;
}
@ -377,7 +377,7 @@ class ClassChecker extends ClassLikeChecker
'Trait ' . $fq_trait_name . ' does not exist',
new CodeLocation($this, $trait)
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
return false;
}
@ -388,7 +388,7 @@ class ClassChecker extends ClassLikeChecker
'Trait ' . $fq_trait_name . ' has wrong casing',
new CodeLocation($this, $trait)
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
return false;
}
@ -614,7 +614,7 @@ class ClassChecker extends ClassLikeChecker
', but no constructor',
$first_uninitialized_property->location
),
$this->source->getSuppressedIssues()
array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
)) {
// fall through
}

View File

@ -12,6 +12,7 @@ use Psalm\Context;
use Psalm\Issue\AbstractInstantiation;
use Psalm\Issue\DeprecatedClass;
use Psalm\Issue\TooManyArguments;
use Psalm\Issue\UndefinedClass;
use Psalm\IssueBuffer;
use Psalm\Type;
use Psalm\Type\Atomic\TNamedObject;
@ -110,6 +111,34 @@ class NewChecker extends \Psalm\Checker\Statements\Expression\CallChecker
) {
$storage = $project_checker->classlike_storage_provider->get($fq_class_name);
foreach ($storage->parent_classes as $parent_class_name) {
if (!$codebase->classlikes->classExists($parent_class_name)) {
if (IssueBuffer::accepts(
new UndefinedClass(
'Parent class ' . $parent_class_name . ' does not exist',
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
}
}
foreach ($storage->class_implements as $interface_name) {
if (!$codebase->classlikes->interfaceExists($interface_name)) {
if (IssueBuffer::accepts(
new UndefinedClass(
'Implemented interface ' . $interface_name . ' does not exist',
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
}
}
// if we're not calling this constructor via new static()
if ($storage->abstract && !$late_static) {
if (IssueBuffer::accepts(

View File

@ -236,6 +236,16 @@ class MethodCallTest extends TestCase
$a->bar();',
'error_message' => 'PossiblyFalseReference',
],
'undefinedParentClass' => [
'<?php
/**
* @psalm-suppress UndefinedClass
*/
class B extends A {}
$b = new B();',
'error_message' => 'UndefinedClass - src/somefile.php:7',
],
];
}
}