1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-29 20:28:59 +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:
Bruce Weirdan 2020-09-13 23:41:14 +03:00 committed by Daniil Gentili
parent 4319132057
commit b27a233cdd
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
4 changed files with 68 additions and 31 deletions

View File

@ -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;
}
}

View File

@ -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
{
@ -644,7 +641,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;
}
}
}
@ -985,7 +984,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;
}
}
}

View File

@ -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
);
}
}
}

View File

@ -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 {