Skip to content

Commit

Permalink
Merge pull request #58 from weirdan/fix-external-dataproviders-when-p…
Browse files Browse the repository at this point in the history
…salm-runs-on-a-single-file

Fix external dataproviders when psalm runs on a single file
  • Loading branch information
weirdan authored Mar 30, 2020
2 parents 496c08f + ed3ea8b commit 30b2242
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 33 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ before_install:
- composer clear-cache

install:
- composer install
- travis_retry composer install
- if [[ "$DEPS" = 'high' || "$DEPS" = 'dev' ]]; then travis_retry composer $DEFAULT_COMPOSER_FLAGS update; fi
- if [[ "$DEPS" = 'high' ]]; then composer require $DEFAULT_COMPOSER_FLAGS --prefer-stable vimeo/psalm; fi
- if [[ "$DEPS" = 'high' ]]; then composer require $DEFAULT_COMPOSER_FLAGS --prefer-stable --update-with-dependencies vimeo/psalm; fi
- if [[ "$DEPS" = 'low' ]]; then travis_retry composer $DEFAULT_COMPOSER_FLAGS --prefer-lowest --prefer-stable update; fi
- if [[ "$DEPS" = 'stable' ]]; then travis_retry composer $DEFAULT_COMPOSER_FLAGS --prefer-stable update; fi
- ./vendor/bin/psalm --version
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"require-dev": {
"squizlabs/php_codesniffer": "^3.3.1",
"codeception/base": "^2.5",
"weirdan/codeception-psalm-module": "^0.2.2"
"weirdan/codeception-psalm-module": "^0.4.0"
},
"extra": {
"psalm": {
Expand Down
41 changes: 27 additions & 14 deletions hooks/TestCaseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
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;
Expand Down Expand Up @@ -76,6 +76,24 @@ public static function afterClassLikeVisit(
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;
}
}
}
}

/**
Expand Down Expand Up @@ -132,7 +150,7 @@ public static function afterStatementAnalysis(
}

$codebase->methodExists(
$declaring_method_id,
(string) $declaring_method_id,
null,
'PHPUnit\Framework\TestSuite::run'
);
Expand Down Expand Up @@ -177,9 +195,9 @@ public static function afterStatementAnalysis(

// methodExists also can mark methods as used (weird, but handy)
$provider_method_exists = $codebase->methodExists(
$provider_method_id,
(string) $provider_method_id,
$provider_docblock_location,
$declaring_method_id
(string) $declaring_method_id
);

if (!$provider_method_exists) {
Expand Down Expand Up @@ -395,15 +413,17 @@ function (
}
}

/** @return Type\Atomic[] */
/** @return non-empty-array<string,Type\Atomic> */
private static function getAtomics(Type\Union $union): array
{
if (method_exists($union, 'getAtomicTypes')) {
/** @var Type\Atomic[] annotated for versions missing the method */
/** @var non-empty-array<string, Type\Atomic> annotated for versions missing the method */
return $union->getAtomicTypes();
} else {
/** @psalm-suppress DeprecatedMethod annotated for newer versions that deprecated the method */
return $union->getTypes();
$types = $union->getTypes();
assert(!empty($types));
return $types;
}
}

Expand Down Expand Up @@ -436,13 +456,6 @@ private static function unionizeIterables(Codebase $codebase, Type\Union $iterab
}
}

if (empty($key_types) || empty($value_types)) {
return new Type\Atomic\TIterable([
Type::getMixed(),
Type::getMixed(),
]);
}

$combine =
/** @param null|Type\Union $a */
function ($a, Type\Union $b) use ($codebase): Type\Union {
Expand Down
23 changes: 8 additions & 15 deletions tests/acceptance/Assert75.feature
Original file line number Diff line number Diff line change
Expand Up @@ -127,24 +127,17 @@ Feature: Assert (PHPUnit 7.5+)
Scenario: Assert::assertIsScalar()
Given I have the following code
"""
/** @psalm-suppress MixedAssignment */
$s = mixed();
/** @return scalar */
function f() {
/** @psalm-suppress MixedAssignment */
$s = mixed();
Assert::assertIsScalar($s); // int|string|float|bool
// all of the following should cause errors
if (is_array($s)) {}
if (is_resource($s)) {}
if (is_object($s)) {}
if (is_null($s)) {}
Assert::assertIsScalar($s);
return $s;
}
"""
When I run Psalm
Then I see these errors
| Type | Message |
| DocblockTypeContradiction | Found a contradiction with a docblock-defined type when evaluating $s and trying to reconcile type 'scalar' to array |
| DocblockTypeContradiction | Cannot resolve types for $s - docblock-defined type scalar does not contain resource |
| DocblockTypeContradiction | Found a contradiction with a docblock-defined type when evaluating $s and trying to reconcile type 'scalar' to object |
| DocblockTypeContradiction | Cannot resolve types for $s - docblock-defined type scalar does not contain null |
And I see no other errors
Then I see no errors

Scenario: Assert::assertIsCallable()
Given I have the following code
Expand Down
34 changes: 33 additions & 1 deletion tests/acceptance/TestCase.feature
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Feature: TestCase
Given I have the following config
"""
<?xml version="1.0"?>
<psalm totallyTyped="true">
<psalm totallyTyped="true" %s>
<projectFiles>
<directory name="."/>
<ignoreFiles> <directory name="../../vendor"/> </ignoreFiles>
Expand Down Expand Up @@ -1176,6 +1176,38 @@ Feature: TestCase
| Type | Message |
| InvalidArgument | Argument 1 of NS\MyTestCase::testSomething expects int, string provided by NS\External::provide():(iterable<string, array<int, string>>) |

@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"
"""
<?php
namespace NS;
use PHPUnit\Framework\TestCase;
class MyTestCase extends TestCase {
/** @dataProvider External::provide */
public function testSomething(int $_p): void {}
}
"""
And I have the following code in "ext.php"
"""
<?php
namespace NS;
class External {
/** @return iterable<string, array<int,int>> */
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
Expand Down

0 comments on commit 30b2242

Please sign in to comment.