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

Fix #3032 - always replay docblock issues when analysing files

This commit is contained in:
Matthew Brown 2020-03-28 19:54:55 -04:00
parent 86a89b2d27
commit 93735712f0
8 changed files with 187 additions and 357 deletions

View File

@ -208,6 +208,10 @@ class ClassAnalyzer extends ClassLikeAnalyzer
); );
} }
foreach ($storage->docblock_issues as $docblock_issue) {
IssueBuffer::add($docblock_issue);
}
$classlike_storage_provider = $codebase->classlike_storage_provider; $classlike_storage_provider = $codebase->classlike_storage_provider;
$parent_fq_class_name = $this->parent_fq_class_name; $parent_fq_class_name = $this->parent_fq_class_name;

View File

@ -180,6 +180,10 @@ class FileAnalyzer extends SourceAnalyzer implements StatementsSource
$this->node_data = new \Psalm\Internal\Provider\NodeDataProvider(); $this->node_data = new \Psalm\Internal\Provider\NodeDataProvider();
$statements_analyzer = new StatementsAnalyzer($this, $this->node_data); $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, // if there are any leftover statements, evaluate them,
// in turn causing the classes/interfaces be evaluated // in turn causing the classes/interfaces be evaluated
if ($leftover_stmts) { if ($leftover_stmts) {

View File

@ -158,6 +158,10 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
} }
} }
foreach ($storage->docblock_issues as $docblock_issue) {
IssueBuffer::add($docblock_issue);
}
$overridden_method_ids = []; $overridden_method_ids = [];
if ($this->function instanceof ClassMethod) { if ($this->function instanceof ClassMethod) {

View File

@ -172,27 +172,15 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->type_aliases += $type_alias_tokens; $this->type_aliases += $type_alias_tokens;
} catch (DocblockParseException $e) { } catch (DocblockParseException $e) {
if (IssueBuffer::accepts( $this->file_storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( (string)$e->getMessage(),
(string)$e->getMessage(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
// fall through
}
$this->file_storage->has_docblock_issues = true;
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $this->file_storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( (string)$e->getMessage(),
(string)$e->getMessage(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
// fall through
}
$this->file_storage->has_docblock_issues = true;
} }
} }
} }
@ -434,15 +422,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
|| isset($comments['specials']['template-implements']) || isset($comments['specials']['template-implements'])
|| isset($comments['specials']['implements']) || isset($comments['specials']['implements'])
) { ) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'You must use @use or @template-use to parameterize traits',
'You must use @use or @template-use to parameterize traits', new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} }
} }
} elseif ($node instanceof PhpParser\Node\Expr\Include_) { } elseif ($node instanceof PhpParser\Node\Expr\Include_) {
@ -664,10 +647,6 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->file_storage->has_visitor_issues = true; $this->file_storage->has_visitor_issues = true;
} }
if ($classlike_storage->has_docblock_issues) {
$this->file_storage->has_docblock_issues = true;
}
if ($node->name) { if ($node->name) {
$this->class_template_types = []; $this->class_template_types = [];
} }
@ -715,10 +694,6 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
if ($functionlike_storage->has_visitor_issues) { if ($functionlike_storage->has_visitor_issues) {
$this->file_storage->has_visitor_issues = true; $this->file_storage->has_visitor_issues = true;
} }
if ($functionlike_storage->has_docblock_issues) {
$this->file_storage->has_docblock_issues = true;
}
} elseif ($node instanceof PhpParser\Node\Stmt\If_ && $node->getLine() === $this->skip_if_descendants) { } elseif ($node instanceof PhpParser\Node\Stmt\If_ && $node->getLine() === $this->skip_if_descendants) {
$this->exists_cond_expr = null; $this->exists_cond_expr = null;
$this->not_exists_cond_expr = null; $this->not_exists_cond_expr = null;
@ -1136,15 +1111,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->aliases $this->aliases
); );
} catch (DocblockParseException $e) { } catch (DocblockParseException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names),
$e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names), $name_location ?: $class_location
$name_location ?: $class_location );
)
)) {
}
$storage->has_docblock_issues = true;
} }
if ($docblock_info) { if ($docblock_info) {
@ -1173,16 +1143,12 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
) )
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for '
$e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names),
. implode('.', $this->fq_classlike_names), $name_location ?: $class_location
$name_location ?: $class_location );
)
)) {
}
$storage->has_docblock_issues = true;
continue; continue;
} }
@ -1190,15 +1156,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$fq_classlike_name => [$template_type], $fq_classlike_name => [$template_type],
]; ];
} else { } else {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Template missing as type',
'Template missing as type', $name_location ?: $class_location
$name_location ?: $class_location );
)
)) {
}
$storage->has_docblock_issues = true;
} }
} else { } else {
/** @psalm-suppress PropertyTypeCoercion due to a Psalm bug */ /** @psalm-suppress PropertyTypeCoercion due to a Psalm bug */
@ -1248,15 +1209,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->pseudo_property_get_types[$property['name']] = $pseudo_property_type; $storage->pseudo_property_get_types[$property['name']] = $pseudo_property_type;
} }
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names),
$e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names), $name_location ?: $class_location
$name_location ?: $class_location );
)
)) {
}
$storage->has_docblock_issues = true;
} }
} }
@ -1282,15 +1238,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
if ($docblock_info->mixin) { if ($docblock_info->mixin) {
if (isset($this->class_template_types[$docblock_info->mixin])) { if (isset($this->class_template_types[$docblock_info->mixin])) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Templates are not currently supported for @mixin',
'Templates are not currently supported for @mixin', $name_location ?: $class_location
$name_location ?: $class_location );
)
)) {
}
$storage->has_docblock_issues = true;
} else { } else {
$storage->mixin_fqcln = Type::getFQCLNFromString( $storage->mixin_fqcln = Type::getFQCLNFromString(
$docblock_info->mixin, $docblock_info->mixin,
@ -1335,15 +1286,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
string $extended_class_name string $extended_class_name
) { ) {
if (trim($extended_class_name) === '') { if (trim($extended_class_name) === '') {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Extended class cannot be empty in docblock for ' . implode('.', $this->fq_classlike_names),
'Extended class cannot be empty in docblock for ' . implode('.', $this->fq_classlike_names), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1360,29 +1306,19 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->class_template_types $this->class_template_types
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names),
$e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
if (!$extended_union_type->isSingle()) { if (!$extended_union_type->isSingle()) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-extends cannot be a union type',
'@template-extends cannot be a union type', new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} }
$extended_union_type->setFromDocblock(); $extended_union_type->setFromDocblock();
@ -1395,15 +1331,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
foreach ($extended_union_type->getAtomicTypes() as $atomic_type) { foreach ($extended_union_type->getAtomicTypes() as $atomic_type) {
if (!$atomic_type instanceof Type\Atomic\TGenericObject) { if (!$atomic_type instanceof Type\Atomic\TGenericObject) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-extends has invalid class ' . $atomic_type->getId(),
'@template-extends has invalid class ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1413,16 +1344,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
if (!isset($storage->parent_classes[$generic_class_lc]) if (!isset($storage->parent_classes[$generic_class_lc])
&& !isset($storage->parent_interfaces[$generic_class_lc]) && !isset($storage->parent_interfaces[$generic_class_lc])
) { ) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-extends must include the name of an extended class,'
'@template-extends must include the name of an extended class,' . ' got ' . $atomic_type->getId(),
. ' got ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} }
$extended_type_parameters = []; $extended_type_parameters = [];
@ -1446,15 +1372,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
string $implemented_class_name string $implemented_class_name
) { ) {
if (trim($implemented_class_name) === '') { if (trim($implemented_class_name) === '') {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Extended class cannot be empty in docblock for ' . implode('.', $this->fq_classlike_names),
'Extended class cannot be empty in docblock for ' . implode('.', $this->fq_classlike_names), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1471,29 +1392,19 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->class_template_types $this->class_template_types
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names),
$e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
if (!$implemented_union_type->isSingle()) { if (!$implemented_union_type->isSingle()) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-implements cannot be a union type',
'@template-implements cannot be a union type', new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1508,15 +1419,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
foreach ($implemented_union_type->getAtomicTypes() as $atomic_type) { foreach ($implemented_union_type->getAtomicTypes() as $atomic_type) {
if (!$atomic_type instanceof Type\Atomic\TGenericObject) { if (!$atomic_type instanceof Type\Atomic\TGenericObject) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-implements has invalid class ' . $atomic_type->getId(),
'@template-implements has invalid class ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1524,16 +1430,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$generic_class_lc = strtolower($atomic_type->value); $generic_class_lc = strtolower($atomic_type->value);
if (!isset($storage->class_implements[$generic_class_lc])) { if (!isset($storage->class_implements[$generic_class_lc])) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-implements must include the name of an implemented class,'
'@template-implements must include the name of an implemented class,' . ' got ' . $atomic_type->getId(),
. ' got ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1559,15 +1460,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
string $used_class_name string $used_class_name
) { ) {
if (trim($used_class_name) === '') { if (trim($used_class_name) === '') {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Extended class cannot be empty in docblock for ' . implode('.', $this->fq_classlike_names),
'Extended class cannot be empty in docblock for ' . implode('.', $this->fq_classlike_names), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1584,29 +1480,19 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->class_template_types $this->class_template_types
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names),
$e->getMessage() . ' in docblock for ' . implode('.', $this->fq_classlike_names), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
if (!$used_union_type->isSingle()) { if (!$used_union_type->isSingle()) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-use cannot be a union type',
'@template-use cannot be a union type', new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1621,15 +1507,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
foreach ($used_union_type->getAtomicTypes() as $atomic_type) { foreach ($used_union_type->getAtomicTypes() as $atomic_type) {
if (!$atomic_type instanceof Type\Atomic\TGenericObject) { if (!$atomic_type instanceof Type\Atomic\TGenericObject) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-use has invalid class ' . $atomic_type->getId(),
'@template-use has invalid class ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1637,16 +1518,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$generic_class_lc = strtolower($atomic_type->value); $generic_class_lc = strtolower($atomic_type->value);
if (!isset($storage->used_traits[$generic_class_lc])) { if (!isset($storage->used_traits[$generic_class_lc])) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( '@template-use must include the name of an used class,'
'@template-use must include the name of an used class,' . ' got ' . $atomic_type->getId(),
. ' got ' . $atomic_type->getId(), new CodeLocation($this->file_scanner, $node, null, true)
new CodeLocation($this->file_scanner, $node, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
return; return;
} }
@ -1901,15 +1777,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
foreach ($stmt->getParams() as $param) { foreach ($stmt->getParams() as $param) {
if ($param->var instanceof PhpParser\Node\Expr\Error) { if ($param->var instanceof PhpParser\Node\Expr\Error) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Param' . ($i + 1) . ' of ' . $cased_function_id . ' has invalid syntax',
'Param' . ($i + 1) . ' of ' . $cased_function_id . ' has invalid syntax', new CodeLocation($this->file_scanner, $param, null, true)
new CodeLocation($this->file_scanner, $param, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
++$i; ++$i;
@ -1919,15 +1790,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$param_array = $this->getTranslatedFunctionParam($param, $stmt, $fake_method, $fq_classlike_name); $param_array = $this->getTranslatedFunctionParam($param, $stmt, $fake_method, $fq_classlike_name);
if (isset($existing_params['$' . $param_array->name])) { if (isset($existing_params['$' . $param_array->name])) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new DuplicateParam(
new DuplicateParam( 'Duplicate param $' . $param_array->name . ' in docblock for ' . $cased_function_id,
'Duplicate param $' . $param_array->name . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $param, null, true)
new CodeLocation($this->file_scanner, $param, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
++$i; ++$i;
@ -2136,26 +2002,17 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
try { try {
$docblock_info = CommentAnalyzer::extractFunctionDocblockInfo($doc_comment); $docblock_info = CommentAnalyzer::extractFunctionDocblockInfo($doc_comment);
} catch (IncorrectDocblockException $e) { } catch (IncorrectDocblockException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new MissingDocblockType(
new MissingDocblockType( $e->getMessage() . ' in docblock for ' . $cased_function_id,
$e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
$docblock_info = null; $docblock_info = null;
} catch (DocblockParseException $e) { } catch (DocblockParseException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . $cased_function_id,
$e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
$docblock_info = null; $docblock_info = null;
} }
@ -2270,28 +2127,18 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->template_types + ($template_types ?: []) $storage->template_types + ($template_types ?: [])
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Template ' . $template_name . ' has invalid as type - ' . $e->getMessage(),
'Template ' . $template_name . ' has invalid as type - ' . $e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
$template_type = Type::getMixed(); $template_type = Type::getMixed();
} }
} else { } else {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Template ' . $template_name . ' missing as type',
'Template ' . $template_name . ' missing as type', new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
$template_type = Type::getMixed(); $template_type = Type::getMixed();
} }
@ -2300,16 +2147,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
} }
if (isset($template_types[$template_name])) { if (isset($template_types[$template_name])) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Duplicate template param ' . $template_name . ' in docblock for '
'Duplicate template param ' . $template_name . ' in docblock for ' . $cased_function_id,
. $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} else { } else {
$storage->template_types[$template_name] = [ $storage->template_types[$template_name] = [
'fn-' . strtolower($cased_function_id) => [$template_type], 'fn-' . strtolower($cased_function_id) => [$template_type],
@ -2328,7 +2170,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->assertions = []; $storage->assertions = [];
foreach ($docblock_info->assertions as $assertion) { foreach ($docblock_info->assertions as $assertion) {
$assertion_type_parts = $this->getAssertionParts($assertion['type'], $stmt); $assertion_type_parts = $this->getAssertionParts(
$storage,
$assertion['type'],
$stmt
);
if (!$assertion_type_parts) { if (!$assertion_type_parts) {
continue; continue;
@ -2355,7 +2201,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->if_true_assertions = []; $storage->if_true_assertions = [];
foreach ($docblock_info->if_true_assertions as $assertion) { foreach ($docblock_info->if_true_assertions as $assertion) {
$assertion_type_parts = $this->getAssertionParts($assertion['type'], $stmt); $assertion_type_parts = $this->getAssertionParts(
$storage,
$assertion['type'],
$stmt
);
if (!$assertion_type_parts) { if (!$assertion_type_parts) {
continue; continue;
@ -2382,7 +2232,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->if_false_assertions = []; $storage->if_false_assertions = [];
foreach ($docblock_info->if_false_assertions as $assertion) { foreach ($docblock_info->if_false_assertions as $assertion) {
$assertion_type_parts = $this->getAssertionParts($assertion['type'], $stmt); $assertion_type_parts = $this->getAssertionParts(
$storage,
$assertion['type'],
$stmt
);
if (!$assertion_type_parts) { if (!$assertion_type_parts) {
continue; continue;
@ -2417,15 +2271,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
null null
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . $cased_function_id,
$e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
continue; continue;
} }
@ -2468,15 +2317,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->function_template_types + $class_template_types $this->function_template_types + $class_template_types
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . $cased_function_id,
$e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
continue; continue;
} }
@ -2630,15 +2474,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$storage->return_type->queueClassLikesForScanning($this->codebase, $this->file_storage); $storage->return_type->queueClassLikesForScanning($this->codebase, $this->file_storage);
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . $cased_function_id,
$e->getMessage() . ' in docblock for ' . $cased_function_id, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} }
if ($storage->return_type && $docblock_info->ignore_nullable_return) { if ($storage->return_type && $docblock_info->ignore_nullable_return) {
@ -2742,6 +2581,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
* @return ?list<string> * @return ?list<string>
*/ */
private function getAssertionParts( private function getAssertionParts(
FunctionLikeStorage $storage,
string $assertion_type, string $assertion_type,
PhpParser\Node\FunctionLike $stmt PhpParser\Node\FunctionLike $stmt
) : ?array { ) : ?array {
@ -2779,16 +2619,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
); );
if ($prefix && count($namespaced_type->getAtomicTypes()) > 1) { if ($prefix && count($namespaced_type->getAtomicTypes()) > 1) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( 'Docblock assertions cannot contain | characters together with ' . $prefix,
'Docblock assertions cannot contain | characters together with ' . $prefix, new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
// do nothing
}
$this->file_storage->has_docblock_issues = true;
return null; return null;
} }
@ -3039,15 +2873,10 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$this->function_template_types + $class_template_types $this->function_template_types + $class_template_types
); );
} catch (TypeParseTreeException $e) { } catch (TypeParseTreeException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage() . ' in docblock for ' . $cased_method_id,
$e->getMessage() . ' in docblock for ' . $cased_method_id, $docblock_type_location
$docblock_type_location );
)
)) {
}
$storage->has_docblock_issues = true;
continue; continue;
} }
@ -3199,25 +3028,15 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$var_comment = array_pop($var_comments); $var_comment = array_pop($var_comments);
} catch (IncorrectDocblockException $e) { } catch (IncorrectDocblockException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new MissingDocblockType(
new MissingDocblockType( $e->getMessage(),
$e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} catch (DocblockParseException $e) { } catch (DocblockParseException $e) {
if (IssueBuffer::accepts( $storage->docblock_issues[] = new InvalidDocblock(
new InvalidDocblock( $e->getMessage(),
$e->getMessage(), new CodeLocation($this->file_scanner, $stmt, null, true)
new CodeLocation($this->file_scanner, $stmt, null, true) );
)
)) {
}
$storage->has_docblock_issues = true;
} }
} }

View File

@ -59,7 +59,6 @@ class FileScanner implements FileSource
if ((!$this->will_analyze || $file_storage->deep_scan) if ((!$this->will_analyze || $file_storage->deep_scan)
&& $storage_from_cache && $storage_from_cache
&& !$file_storage->has_docblock_issues
&& !$codebase->register_stub_files && !$codebase->register_stub_files
) { ) {
return; return;

View File

@ -384,9 +384,9 @@ class ClassLikeStorage
public $has_visitor_issues = false; public $has_visitor_issues = false;
/** /**
* @var bool * @var list<\Psalm\Issue\CodeIssue>
*/ */
public $has_docblock_issues = false; public $docblock_issues = [];
/** /**
* @param string $name * @param string $name

View File

@ -77,9 +77,9 @@ class FileStorage
public $has_visitor_issues = false; public $has_visitor_issues = false;
/** /**
* @var bool * @var list<\Psalm\Issue\CodeIssue>
*/ */
public $has_docblock_issues = false; public $docblock_issues = [];
/** /**
* @var array<string, array<int, array{0: string, 1: int}>> * @var array<string, array<int, array{0: string, 1: int}>>

View File

@ -142,9 +142,9 @@ class FunctionLikeStorage
public $has_visitor_issues = false; public $has_visitor_issues = false;
/** /**
* @var bool * @var list<\Psalm\Issue\CodeIssue>
*/ */
public $has_docblock_issues = false; public $docblock_issues = [];
/** /**
* @var array<string, bool> * @var array<string, bool>