mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Delay checks for MissingPropertyType so we can give more useful messages
This commit is contained in:
parent
ce6ca58291
commit
60be6f07a0
@ -605,6 +605,12 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($trait_checker->class->stmts as $trait_stmt) {
|
||||
if ($trait_stmt instanceof PhpParser\Node\Stmt\Property) {
|
||||
$this->checkForMissingPropertyType($trait_stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -688,7 +694,11 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->class->stmts as $stmt) {
|
||||
if ($stmt instanceof PhpParser\Node\Stmt\Property) {
|
||||
$this->checkForMissingPropertyType($stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1012,17 +1022,6 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
} elseif (!$comment || !$comment->getText()) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingPropertyType(
|
||||
'Property ' . $this->fq_class_name . '::$' . $stmt->props[0]->name . ' does not have a ' .
|
||||
'declared type',
|
||||
new CodeLocation($this, $stmt)
|
||||
),
|
||||
$this->source->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
|
||||
$property_group_type = $type_in_comment ?: null;
|
||||
@ -1075,6 +1074,41 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Stmt\Property $stmt
|
||||
* @return void
|
||||
*/
|
||||
private function checkForMissingPropertyType(PhpParser\Node\Stmt\Property $stmt)
|
||||
{
|
||||
$comment = $stmt->getDocComment();
|
||||
$type_in_comment = null;
|
||||
$property_type_line_number = null;
|
||||
$storage = self::$storage[strtolower($this->fq_class_name)];
|
||||
|
||||
if (!$comment || !$comment->getText()) {
|
||||
$fq_class_name = $this->fq_class_name;
|
||||
$property_name = $stmt->props[0]->name;
|
||||
|
||||
$message = 'Property ' . $fq_class_name . '::$' . $property_name . ' does not have a declared type';
|
||||
|
||||
$property_storage = ClassLikeChecker::$storage[strtolower($fq_class_name)]->properties[$property_name];
|
||||
|
||||
if ($property_storage->suggested_type) {
|
||||
$message .= ' - consider ' . $property_storage->suggested_type;
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingPropertyType(
|
||||
$message,
|
||||
new CodeLocation($this, $stmt)
|
||||
),
|
||||
$this->source->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PhpParser\Node\Stmt\ClassConst $stmt
|
||||
* @param Context $class_context
|
||||
|
@ -671,18 +671,19 @@ class AssignmentChecker
|
||||
$class_property_type = $property_storage->type;
|
||||
|
||||
if ($class_property_type === false) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingPropertyType(
|
||||
'Property ' . $lhs_type_part->value . '::$' . $prop_name . ' does not have a declared ' .
|
||||
'type',
|
||||
new CodeLocation($statements_checker->getSource(), $stmt)
|
||||
),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
$class_property_type = Type::getMixed();
|
||||
|
||||
if (!$assignment_value_type->isMixed()) {
|
||||
if ($property_storage->suggested_type) {
|
||||
$property_storage->suggested_type = Type::combineUnionTypes(
|
||||
$assignment_value_type,
|
||||
$property_storage->suggested_type
|
||||
);
|
||||
} else {
|
||||
$property_storage->suggested_type = $assignment_value_type;
|
||||
}
|
||||
}
|
||||
|
||||
$class_property_type = Type::getMixed();
|
||||
} else {
|
||||
$class_property_type = ExpressionChecker::fleshOutTypes(
|
||||
clone $class_property_type,
|
||||
@ -848,17 +849,18 @@ class AssignmentChecker
|
||||
$class_property_type = $property_storage->type;
|
||||
|
||||
if ($class_property_type === false) {
|
||||
if (IssueBuffer::accepts(
|
||||
new MissingPropertyType(
|
||||
'Property ' . $fq_class_name . '::$' . $prop_name . ' does not have a declared type',
|
||||
new CodeLocation($statements_checker->getSource(), $stmt)
|
||||
),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
|
||||
$class_property_type = Type::getMixed();
|
||||
|
||||
if (!$assignment_value_type->isMixed()) {
|
||||
if ($property_storage->suggested_type) {
|
||||
$property_storage->suggested_type = Type::combineUnionTypes(
|
||||
$assignment_value_type,
|
||||
$property_storage->suggested_type
|
||||
);
|
||||
} else {
|
||||
$property_storage->suggested_type = $assignment_value_type;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$class_property_type = clone $class_property_type;
|
||||
}
|
||||
|
@ -31,6 +31,11 @@ class PropertyStorage
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @var Type\Union|null
|
||||
*/
|
||||
public $suggested_type;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -206,7 +206,7 @@ class PropertyTypeTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Psalm\Exception\CodeException
|
||||
* @expectedExceptionMessage MissingPropertyType
|
||||
* @expectedExceptionMessage MissingPropertyType - somefile.php:3 - Property A::$foo does not have a declared type - consider int
|
||||
* @return void
|
||||
*/
|
||||
public function testMissingPropertyType()
|
||||
@ -214,6 +214,10 @@ class PropertyTypeTest extends PHPUnit_Framework_TestCase
|
||||
$stmts = self::$parser->parse('<?php
|
||||
class A {
|
||||
public $foo;
|
||||
|
||||
public function assignToFoo() : void {
|
||||
$this->foo = 5;
|
||||
}
|
||||
}
|
||||
');
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user