From 064d4886c3acafb74297dc2b623bf7c097e50c56 Mon Sep 17 00:00:00 2001 From: bugreportuser <37939393+bugreportuser@users.noreply.github.com> Date: Fri, 4 Oct 2019 14:01:58 -0400 Subject: [PATCH] Track exception suppressions (#2211) --- src/Psalm/Context.php | 11 ++- tests/IssueSuppressionTest.php | 127 +++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/Psalm/Context.php b/src/Psalm/Context.php index 1ccf11157..05b326f9b 100644 --- a/src/Psalm/Context.php +++ b/src/Psalm/Context.php @@ -16,6 +16,8 @@ use Psalm\Internal\Type\AssertionReconciler; use Psalm\Type\Union; use function strpos; use function strtolower; +use function array_search; +use function is_int; class Context { @@ -812,7 +814,14 @@ class Context $issue_type = $this->is_global ? 'UncaughtThrowInGlobalScope' : 'MissingThrowsDocblock'; $suppressed_issues = $statements_analyzer->getSuppressedIssues(); - if (in_array($issue_type, $suppressed_issues, true)) { + $suppressed_issue_position = array_search($issue_type, $suppressed_issues, true); + if ($suppressed_issue_position !== false) { + if (is_int($suppressed_issue_position)) { + $file = $statements_analyzer->getFileAnalyzer()->getFilePath(); + IssueBuffer::addUsedSuppressions([ + $file => [$suppressed_issue_position => true], + ]); + } return true; } diff --git a/tests/IssueSuppressionTest.php b/tests/IssueSuppressionTest.php index 032cd0461..07ac843a8 100644 --- a/tests/IssueSuppressionTest.php +++ b/tests/IssueSuppressionTest.php @@ -2,6 +2,8 @@ namespace Psalm\Tests; use const DIRECTORY_SEPARATOR; +use Psalm\Config; +use Psalm\Context; class IssueSuppressionTest extends TestCase { @@ -53,6 +55,131 @@ class IssueSuppressionTest extends TestCase $this->analyzeFile('somefile.php', new \Psalm\Context()); } + /** + * @return void + */ + public function testMissingThrowsDocblockSuppressed() + { + Config::getInstance()->check_for_throws_docblock = true; + + $this->addFile( + 'somefile.php', + 'analyzeFile('somefile.php', $context); + } + + /** + * @return void + */ + public function testMissingThrowsDocblockSuppressedWithoutThrow() + { + $this->expectException(\Psalm\Exception\CodeException::class); + $this->expectExceptionMessage('UnusedPsalmSuppress'); + Config::getInstance()->check_for_throws_docblock = true; + + $this->addFile( + 'somefile.php', + 'analyzeFile('somefile.php', $context); + } + + /** + * @return void + */ + public function testMissingThrowsDocblockSuppressedDuplicate() + { + $this->expectException(\Psalm\Exception\CodeException::class); + $this->expectExceptionMessage('UnusedPsalmSuppress'); + Config::getInstance()->check_for_throws_docblock = true; + + $this->addFile( + 'somefile.php', + 'analyzeFile('somefile.php', $context); + } + + /** + * @return void + */ + public function testUncaughtThrowInGlobalScopeSuppressed() + { + Config::getInstance()->check_for_throws_in_global_scope = true; + + $this->addFile( + 'somefile.php', + 'analyzeFile('somefile.php', $context); + } + + /** + * @return void + */ + public function testUncaughtThrowInGlobalScopeSuppressedWithoutThrow() + { + $this->expectException(\Psalm\Exception\CodeException::class); + $this->expectExceptionMessage('UnusedPsalmSuppress'); + Config::getInstance()->check_for_throws_in_global_scope = true; + + $this->addFile( + 'somefile.php', + 'analyzeFile('somefile.php', $context); + } + /** * @return iterable,error_levels?:string[]}> */