From 8f981353649e14c7d727f08667200ef50f8e1932 Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Mon, 30 Mar 2020 04:50:31 +0300 Subject: [PATCH] Store external dataprovider references in afterClassLikeVisit This fixes false-positive UndefinedClass issues when Psalm is run on a single test file with cold cache. Fixes psalm/psalm-plugin-phpunit#57 --- hooks/TestCaseHandler.php | 20 +++++++++++++++++- tests/acceptance/TestCase.feature | 34 ++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/hooks/TestCaseHandler.php b/hooks/TestCaseHandler.php index bda0441..42a7d2c 100644 --- a/hooks/TestCaseHandler.php +++ b/hooks/TestCaseHandler.php @@ -7,11 +7,11 @@ namespace Psalm\PhpUnitPlugin\Hooks; use PHPUnit\Framework\TestCase; use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; -use Psalm\CodeLocation; use Psalm\Codebase; use Psalm\DocComment; use Psalm\Exception\DocblockParseException; use Psalm\FileSource; +use Psalm\Internal\PhpVisitor\ReflectorVisitor; use Psalm\IssueBuffer; use Psalm\Issue; use Psalm\Plugin\Hook\AfterClassLikeAnalysisInterface; @@ -76,6 +76,24 @@ class TestCaseHandler implements if (self::hasInitializers($class_storage, $class_node)) { $class_storage->custom_metadata[__NAMESPACE__] = ['hasInitializers' => true]; } + + $file_path = $statements_source->getFilePath(); + $file_storage = $codebase->file_storage_provider->get($file_path); + + foreach ($class_node->getMethods() as $method) { + $specials = self::getSpecials($method); + if (!isset($specials['dataProvider'])) { + continue; + } + foreach ($specials['dataProvider'] as $provider) { + if (false !== strpos($provider, '::')) { + [$class_name] = explode('::', $provider); + $fq_class_name = Type::getFQCLNFromString($class_name, $statements_source->getAliases()); + $codebase->scanner->queueClassLikeForScanning($fq_class_name, $file_path); + $file_storage->referenced_classlikes[strtolower($fq_class_name)] = $fq_class_name; + } + } + } } /** diff --git a/tests/acceptance/TestCase.feature b/tests/acceptance/TestCase.feature index 6a9a59b..6428f92 100644 --- a/tests/acceptance/TestCase.feature +++ b/tests/acceptance/TestCase.feature @@ -7,7 +7,7 @@ Feature: TestCase Given I have the following config """ - + @@ -1176,6 +1176,38 @@ Feature: TestCase | Type | Message | | InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\External::provide():(iterable>) | + @ExternalProviders + Scenario: External providers are available even when Psalm is asked to analyze single test case + Given I have the following code in "test.php" + """ + > */ + public function provide(): iterable { + yield "dataset name" => [1]; + } + } + """ + And I have the following classmap + | Class | File | + | NS\MyTestCase | test.php | + | NS\External | ext.php | + When I run Psalm on "test.php" + Then I see no errors + @List Scenario: Providers returning list are ok Given I have the following code