mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Support multiple issue types in @psalm-suppress
(#4179)
* Accept multiple issue names in `@psalm-suppress` Fixes vimeo/psalm#1575 * Accept multiple issue types on statement docblocks as well * Proper highlighting of individual issues in compound suppressions
This commit is contained in:
parent
cd110c7e2f
commit
689027c92d
@ -197,4 +197,41 @@ class DocComment
|
||||
|
||||
return $parsed_docblock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
* @return array<int,string>
|
||||
*/
|
||||
public static function parseSuppressList(string $suppress_entry): array
|
||||
{
|
||||
preg_match(
|
||||
'/
|
||||
(?(DEFINE)
|
||||
# either a single issue or comma separated list of issues
|
||||
(?<issue_list> (?&issue) \s* , \s* (?&issue_list) | (?&issue) )
|
||||
|
||||
# definition of a single issue
|
||||
(?<issue> [A-Za-z0-9_-]+ )
|
||||
)
|
||||
^ (?P<issues> (?&issue_list) ) (?P<description> .* ) $
|
||||
/xm',
|
||||
$suppress_entry,
|
||||
$matches
|
||||
);
|
||||
|
||||
if (!isset($matches['issues'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$issue_offset = 0;
|
||||
$ret = [];
|
||||
|
||||
foreach (explode(',', $matches['issues']) as $suppressed_issue) {
|
||||
$issue_offset += strspn($suppressed_issue, "\t\n\f\r ");
|
||||
$ret[$issue_offset] = trim($suppressed_issue);
|
||||
$issue_offset += strlen($suppressed_issue) + 1;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
@ -357,10 +357,7 @@ class CommentAnalyzer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $line_number
|
||||
*
|
||||
* @throws DocblockParseException if there was a problem parsing the docblock
|
||||
*
|
||||
*/
|
||||
public static function extractFunctionDocblockInfo(PhpParser\Comment\Doc $comment): FunctionDocblockComment
|
||||
{
|
||||
@ -629,7 +626,9 @@ class CommentAnalyzer
|
||||
|
||||
if (isset($parsed_docblock->tags['psalm-suppress'])) {
|
||||
foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) {
|
||||
$info->suppressed_issues[$offset + $comment->getFilePos()] = preg_split('/[\s]+/', $suppress_entry)[0];
|
||||
foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) {
|
||||
$info->suppressed_issues[$issue_offset + $offset + $comment->getFilePos()] = $suppressed_issue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -970,7 +969,9 @@ class CommentAnalyzer
|
||||
|
||||
if (isset($parsed_docblock->tags['psalm-suppress'])) {
|
||||
foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) {
|
||||
$info->suppressed_issues[$offset + $comment->getFilePos()] = preg_split('/[\s]+/', $suppress_entry)[0];
|
||||
foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) {
|
||||
$info->suppressed_issues[$issue_offset + $offset + $comment->getFilePos()] = $suppressed_issue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,37 +342,25 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
|
||||
}
|
||||
|
||||
if (isset($statements_analyzer->parsed_docblock->tags['psalm-suppress'])) {
|
||||
$suppressed = array_filter(
|
||||
array_map(
|
||||
/**
|
||||
* @param string $line
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function ($line): string {
|
||||
return preg_split('/[\s]+/', $line)[0];
|
||||
},
|
||||
$statements_analyzer->parsed_docblock->tags['psalm-suppress']
|
||||
)
|
||||
);
|
||||
|
||||
$suppressed = $statements_analyzer->parsed_docblock->tags['psalm-suppress'];
|
||||
if ($suppressed) {
|
||||
$new_issues = [];
|
||||
|
||||
foreach ($suppressed as $offset => $issue_type) {
|
||||
$offset += $docblock->getFilePos();
|
||||
$new_issues[$offset] = $issue_type;
|
||||
foreach ($suppressed as $offset => $suppress_entry) {
|
||||
foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $issue_type) {
|
||||
$new_issues[$issue_offset + $offset + $docblock->getFilePos()] = $issue_type;
|
||||
|
||||
if ($issue_type === 'InaccessibleMethod') {
|
||||
continue;
|
||||
}
|
||||
if ($issue_type === 'InaccessibleMethod') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($codebase->track_unused_suppressions) {
|
||||
IssueBuffer::addUnusedSuppression(
|
||||
$statements_analyzer->getFilePath(),
|
||||
$offset,
|
||||
$issue_type
|
||||
);
|
||||
if ($codebase->track_unused_suppressions) {
|
||||
IssueBuffer::addUnusedSuppression(
|
||||
$statements_analyzer->getFilePath(),
|
||||
$issue_offset + $offset + $docblock->getFilePos(),
|
||||
$issue_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,6 +210,17 @@ class IssueSuppressionTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'multipleIssues' => [
|
||||
'<?php
|
||||
class A {
|
||||
/**
|
||||
* @psalm-suppress UndefinedClass, MixedMethodCall,MissingReturnType because reasons
|
||||
*/
|
||||
public function b() {
|
||||
B::fooFoo()->barBar()->bat()->baz()->bam()->bas()->bee()->bet()->bes()->bis();
|
||||
}
|
||||
}',
|
||||
],
|
||||
'undefinedClassOneLine' => [
|
||||
'<?php
|
||||
class A {
|
||||
|
Loading…
Reference in New Issue
Block a user