mirror of
https://github.com/danog/psalm-plugin-phpunit.git
synced 2024-12-02 09:27:56 +01:00
Merge pull request #17 from weirdan/fix-grandchild-missingconstructor
Fix MissingConstructor on TestCase grandchildren
This commit is contained in:
commit
24571b9a0c
@ -4,6 +4,7 @@ namespace Psalm\PhpUnitPlugin\Hooks;
|
|||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use PhpParser\Node\Stmt\ClassLike;
|
use PhpParser\Node\Stmt\ClassLike;
|
||||||
use PhpParser\Node\Stmt\ClassMethod;
|
use PhpParser\Node\Stmt\ClassMethod;
|
||||||
|
use Psalm\CodeLocation;
|
||||||
use Psalm\Codebase;
|
use Psalm\Codebase;
|
||||||
use Psalm\DocComment;
|
use Psalm\DocComment;
|
||||||
use Psalm\FileSource;
|
use Psalm\FileSource;
|
||||||
@ -11,6 +12,7 @@ use Psalm\IssueBuffer;
|
|||||||
use Psalm\Issue;
|
use Psalm\Issue;
|
||||||
use Psalm\PhpUnitPlugin\Exception\UnsupportedPsalmVersion;
|
use Psalm\PhpUnitPlugin\Exception\UnsupportedPsalmVersion;
|
||||||
use Psalm\Plugin\Hook\AfterClassLikeAnalysisInterface;
|
use Psalm\Plugin\Hook\AfterClassLikeAnalysisInterface;
|
||||||
|
use Psalm\Plugin\Hook\AfterClassLikeExistenceCheckInterface;
|
||||||
use Psalm\Plugin\Hook\AfterClassLikeVisitInterface;
|
use Psalm\Plugin\Hook\AfterClassLikeVisitInterface;
|
||||||
use Psalm\StatementsSource;
|
use Psalm\StatementsSource;
|
||||||
use Psalm\Storage\ClassLikeStorage;
|
use Psalm\Storage\ClassLikeStorage;
|
||||||
@ -19,24 +21,54 @@ use Psalm\Storage\MethodStorage;
|
|||||||
use Psalm\Type;
|
use Psalm\Type;
|
||||||
use Psalm\Type\Atomic\TIterable;
|
use Psalm\Type\Atomic\TIterable;
|
||||||
|
|
||||||
class TestCaseHandler implements AfterClassLikeVisitInterface, AfterClassLikeAnalysisInterface
|
class TestCaseHandler implements
|
||||||
|
AfterClassLikeVisitInterface,
|
||||||
|
AfterClassLikeAnalysisInterface,
|
||||||
|
AfterClassLikeExistenceCheckInterface
|
||||||
{
|
{
|
||||||
|
/** @var bool */
|
||||||
|
private static $suppressed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: move to new hook (afterCodebasePopulation?)
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public static function afterClassLikeExistenceCheck(
|
||||||
|
string $fq_class_name,
|
||||||
|
CodeLocation $code_location,
|
||||||
|
StatementsSource $statements_source,
|
||||||
|
Codebase $codebase,
|
||||||
|
array &$file_replacements = []
|
||||||
|
) {
|
||||||
|
if (self::$suppressed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self::$suppressed = true;
|
||||||
|
|
||||||
|
foreach ($codebase->classlike_storage_provider->getAll() as $name => $storage) {
|
||||||
|
$meta = (array) ($storage->custom_metadata[__NAMESPACE__] ?? []);
|
||||||
|
if ($codebase->classExtends($name, TestCase::class) && ($meta['hasInitializers'] ?? false)) {
|
||||||
|
$storage->suppressed_issues[] = 'MissingConstructor';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public static function afterClassLikeVisit(
|
public static function afterClassLikeVisit(
|
||||||
ClassLike $classNode,
|
ClassLike $class_node,
|
||||||
ClassLikeStorage $classStorage,
|
ClassLikeStorage $class_storage,
|
||||||
FileSource $statements_source,
|
FileSource $statements_source,
|
||||||
Codebase $codebase,
|
Codebase $codebase,
|
||||||
array &$file_replacements = []
|
array &$file_replacements = []
|
||||||
) {
|
) {
|
||||||
if (!$codebase->classExtends($classStorage->name, TestCase::class)) {
|
if (self::hasInitializers($class_storage, $class_node)) {
|
||||||
return;
|
if (!isset($class_storage->custom_metadata)) {
|
||||||
|
/** @psalm-suppress UndefinedPropertyAssignment */
|
||||||
|
$class_storage->custom_metadata = [];
|
||||||
}
|
}
|
||||||
|
$class_storage->custom_metadata[__NAMESPACE__] = ['hasInitializers' => true];
|
||||||
if (self::hasInitializers($classStorage, $classNode)) {
|
|
||||||
$classStorage->suppressed_issues[] = 'MissingConstructor';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +412,7 @@ class TestCaseHandler implements AfterClassLikeVisitInterface, AfterClassLikeAna
|
|||||||
foreach ($storage->methods as $method => $_) {
|
foreach ($storage->methods as $method => $_) {
|
||||||
$stmt_method = $stmt->getMethod($method);
|
$stmt_method = $stmt->getMethod($method);
|
||||||
if (!$stmt_method) {
|
if (!$stmt_method) {
|
||||||
throw new \RuntimeException('Failed to find ' . $method);
|
continue;
|
||||||
}
|
}
|
||||||
if (self::isBeforeInitializer($stmt_method)) {
|
if (self::isBeforeInitializer($stmt_method)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -650,3 +650,33 @@ Feature: TestCase
|
|||||||
| Type | Message |
|
| Type | Message |
|
||||||
| InvalidArgument | Argument 1 of NS\MyTestCase::testSomething has no default value, but possibly undefined int provided by NS\MyTestCase::provide():(iterable<string, array{0?:int}>) |
|
| InvalidArgument | Argument 1 of NS\MyTestCase::testSomething has no default value, but possibly undefined int provided by NS\MyTestCase::provide():(iterable<string, array{0?:int}>) |
|
||||||
And I see no other errors
|
And I see no other errors
|
||||||
|
|
||||||
|
Scenario: Stateful grandchild test case with setUp produces no MissingConstructor
|
||||||
|
Given I have the following code
|
||||||
|
"""
|
||||||
|
use Prophecy\Prophecy\ObjectProphecy;
|
||||||
|
|
||||||
|
class BaseTestCase extends TestCase {}
|
||||||
|
|
||||||
|
interface I { public function work(): int; }
|
||||||
|
|
||||||
|
class MyTestCase extends BaseTestCase
|
||||||
|
{
|
||||||
|
/** @var ObjectProphecy<I> */
|
||||||
|
private $i;
|
||||||
|
|
||||||
|
/** @return void */
|
||||||
|
public function setUp() {
|
||||||
|
$this->i = $this->prophesize(I::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return void */
|
||||||
|
public function testSomething() {
|
||||||
|
$this->i->work()->willReturn(1);;
|
||||||
|
$i = $this->i->reveal();
|
||||||
|
$this->assertEquals(1, $i->work());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
When I run Psalm
|
||||||
|
Then I see no errors
|
||||||
|
Loading…
Reference in New Issue
Block a user