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

Fix #2 - suppress errors for single lines

This commit is contained in:
Matt Brown 2017-10-26 18:19:19 -04:00
parent d06e844748
commit 8b7d82ddf6
8 changed files with 237 additions and 1 deletions

View File

@ -33,7 +33,7 @@ class FileChecker extends SourceChecker implements StatementsSource
protected $actual_file_path; protected $actual_file_path;
/** /**
* @var array<string, string> * @var array<int, string>
*/ */
protected $suppressed_issues = []; protected $suppressed_issues = [];
@ -497,6 +497,26 @@ class FileChecker extends SourceChecker implements StatementsSource
return $this->suppressed_issues; return $this->suppressed_issues;
} }
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function addSuppressedIssues(array $new_issues)
{
$this->suppressed_issues = array_merge($new_issues, $this->suppressed_issues);
}
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function removeSuppressedIssues(array $new_issues)
{
$this->suppressed_issues = array_diff($this->suppressed_issues, $new_issues);
}
public function getFQCLN() public function getFQCLN()
{ {
return null; return null;

View File

@ -1321,6 +1321,26 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
return $this->suppressed_issues; return $this->suppressed_issues;
} }
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function addSuppressedIssues(array $new_issues)
{
$this->suppressed_issues = array_merge($new_issues, $this->suppressed_issues);
}
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function removeSuppressedIssues(array $new_issues)
{
$this->suppressed_issues = array_diff($this->suppressed_issues, $new_issues);
}
/** /**
* Adds a suppressed issue, useful when creating a method checker from scratch * Adds a suppressed issue, useful when creating a method checker from scratch
* *

View File

@ -161,6 +161,34 @@ abstract class SourceChecker implements StatementsSource
return $this->source->getSuppressedIssues(); return $this->source->getSuppressedIssues();
} }
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function addSuppressedIssues(array $new_issues)
{
if ($this->source === null) {
throw new \UnexpectedValueException('$source cannot be null');
}
return $this->source->addSuppressedIssues($new_issues);
}
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function removeSuppressedIssues(array $new_issues)
{
if ($this->source === null) {
throw new \UnexpectedValueException('$source cannot be null');
}
return $this->source->removeSuppressedIssues($new_issues);
}
/** /**
* @return string * @return string
*/ */

View File

@ -129,6 +129,33 @@ class StatementsChecker extends SourceChecker implements StatementsSource
} }
*/ */
$new_issues = null;
if ($docblock = $stmt->getDocComment()) {
$comments = CommentChecker::parseDocComment((string)$docblock);
if (isset($comments['specials']['psalm-suppress'])) {
$suppressed = array_filter(
array_map(
/**
* @param string $line
*
* @return string
*/
function ($line) {
return explode(' ', trim($line))[0];
},
$comments['specials']['psalm-suppress']
)
);
if ($suppressed) {
$new_issues = array_diff($suppressed, $this->source->getSuppressedIssues());
/** @psalm-suppress TypeCoercion */
$this->addSuppressedIssues($new_issues);
}
}
}
if ($stmt instanceof PhpParser\Node\Stmt\If_) { if ($stmt instanceof PhpParser\Node\Stmt\If_) {
IfChecker::analyze($this, $stmt, $context, $loop_context); IfChecker::analyze($this, $stmt, $context, $loop_context);
} elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) { } elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) {
@ -348,6 +375,11 @@ class StatementsChecker extends SourceChecker implements StatementsSource
return false; return false;
} }
} }
if ($new_issues) {
/** @psalm-suppress TypeCoercion */
$this->removeSuppressedIssues($new_issues);
}
} }
return null; return null;

View File

@ -82,4 +82,18 @@ interface StatementsSource
* @return array<int, string> * @return array<int, string>
*/ */
public function getSuppressedIssues(); public function getSuppressedIssues();
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function addSuppressedIssues(array $new_issues);
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function removeSuppressedIssues(array $new_issues);
} }

View File

@ -140,4 +140,22 @@ class TraitSource implements StatementsSource
{ {
return []; return [];
} }
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function addSuppressedIssues(array $new_issues)
{
}
/**
* @param array<int, string> $new_issues
*
* @return void
*/
public function removeSuppressedIssues(array $new_issues)
{
}
} }

54
tests/AssertTest.php Normal file
View File

@ -0,0 +1,54 @@
<?php
namespace Psalm\Tests;
class AssertTest extends TestCase
{
use Traits\FileCheckerInvalidCodeParseTestTrait;
use Traits\FileCheckerValidCodeParseTestTrait;
/**
* @return array
*/
public function providerFileCheckerValidCodeParse()
{
return [
'assertInstanceOfB' => [
'<?php
class A {}
class B extends A {
public function foo() : void {}
}
function assertInstanceOfB(A $var) : void {
if (!$var instanceof B) {
throw new \Exception();
}
}
function assertInstanceOfClass(A $var, string $class) : void {
if (!$var instanceof $class) {
throw new \Exception();
}
}
function takesA(A $a) : void {
assertInstanceOfB($a);
$a->foo();
}
function takesA(A $a) : void {
assertInstanceOfB($a);
$a->foo();
}',
],
];
}
/**
* @return array
*/
public function providerFileCheckerInvalidCodeParse()
{
return [];
}
}

View File

@ -4,6 +4,7 @@ namespace Psalm\Tests;
class IssueSuppressionTest extends TestCase class IssueSuppressionTest extends TestCase
{ {
use Traits\FileCheckerValidCodeParseTestTrait; use Traits\FileCheckerValidCodeParseTestTrait;
use Traits\FileCheckerInvalidCodeParseTestTrait;
/** /**
* @return array * @return array
@ -24,6 +25,24 @@ class IssueSuppressionTest extends TestCase
} }
}', }',
], ],
'undefinedClassOneLine' => [
'<?php
class A {
public function b() : void {
/**
* @psalm-suppress UndefinedClass
*/
new B();
}
}',
],
'undefinedClassOneLineInFile' => [
'<?php
/**
* @psalm-suppress UndefinedClass
*/
new B();',
],
'excludeIssue' => [ 'excludeIssue' => [
'<?php '<?php
fooFoo();', fooFoo();',
@ -32,4 +51,35 @@ class IssueSuppressionTest extends TestCase
], ],
]; ];
} }
/**
* @return array
*/
public function providerFileCheckerInvalidCodeParse()
{
return [
'undefinedClassOneLineWithLineAfter' => [
'<?php
class A {
public function b() {
/**
* @psalm-suppress UndefinedClass
*/
new B();
new C();
}
}',
'error_message' => 'UndefinedClass - src/somefile.php:8 - Class or interface C',
],
'undefinedClassOneLineInFileAfter' => [
'<?php
/**
* @psalm-suppress UndefinedClass
*/
new B();
new C();',
'error_message' => 'UndefinedClass - src/somefile.php:6 - Class or interface C',
],
];
}
} }