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

Allow omitting argument offsets for map-type overrides in phpstorm.meta

Fixes vimeo/psalm#8758
This commit is contained in:
Bruce Weirdan 2022-11-27 05:19:05 -04:00
parent 94dac9f9e7
commit de96494fee
No known key found for this signature in database
GPG Key ID: CFC3AAB181751B0D
3 changed files with 107 additions and 6 deletions

View File

@ -89,15 +89,22 @@ class PhpStormMetaScanner
if ($identifier instanceof PhpParser\Node\Expr\StaticCall
&& $identifier->class instanceof PhpParser\Node\Name\FullyQualified
&& $identifier->name instanceof PhpParser\Node\Identifier
&& $identifier->getArgs()
&& $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber
&& (
$identifier->getArgs() === []
|| $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber
)
) {
$meta_fq_classlike_name = implode('\\', $identifier->class->parts);
$meta_method_name = strtolower($identifier->name->name);
if ($map) {
$offset = $identifier->getArgs()[0]->value->value;
$offset = 0;
if ($identifier->getArgs()
&& $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber
) {
$offset = $identifier->getArgs()[0]->value->value;
}
$codebase->methods->return_type_provider->registerClosure(
$meta_fq_classlike_name,
@ -248,13 +255,20 @@ class PhpStormMetaScanner
if ($identifier instanceof PhpParser\Node\Expr\FuncCall
&& $identifier->name instanceof PhpParser\Node\Name\FullyQualified
&& $identifier->getArgs()
&& $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber
&& (
$identifier->getArgs() === []
|| $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber
)
) {
$function_id = strtolower(implode('\\', $identifier->name->parts));
if ($map) {
$offset = $identifier->getArgs()[0]->value->value;
$offset = 0;
if ($identifier->getArgs()
&& $identifier->getArgs()[0]->value instanceof PhpParser\Node\Scalar\LNumber
) {
$offset = $identifier->getArgs()[0]->value->value;
}
$codebase->functions->return_type_provider->registerClosure(
$function_id,

View File

@ -22,6 +22,9 @@ use function explode;
use function getcwd;
use function implode;
use function reset;
use function strlen;
use function strpos;
use function substr;
use const DIRECTORY_SEPARATOR;
@ -321,6 +324,12 @@ class StubTest extends TestCase
*/
public function create(string $s) {}
/**
* @return mixed
* @psalm-suppress InvalidReturnType
*/
public function create2(string $s) {}
/**
* @param mixed $s
* @return mixed
@ -342,6 +351,12 @@ class StubTest extends TestCase
*/
function create(string $s) {}
/**
* @return mixed
* @psalm-suppress InvalidReturnType
*/
function create2(string $s) {}
/**
* @param mixed $s
* @return mixed
@ -358,11 +373,19 @@ class StubTest extends TestCase
$a1 = (new \Ns\MyClass)->creAte("object");
$a2 = (new \Ns\MyClass)->creaTe("exception");
$y1 = (new \Ns\MyClass)->creAte2("object");
$y2 = (new \Ns\MyClass)->creaTe2("exception");
$b1 = \Create("object");
$b2 = \cReate("exception");
$e2 = \creAte(\LogicException::class);
$z1 = \Create2("object");
$z2 = \cReate2("exception");
$x2 = \creAte2(\LogicException::class);
$c1 = (new \Ns\MyClass)->foo(5);
$c2 = (new \Ns\MyClass)->bar(["hello"]);
@ -373,6 +396,57 @@ class StubTest extends TestCase
$context = new Context();
$this->analyzeFile($file_path, $context);
$this->assertContextVars(
[
'$a1===' => 'stdClass',
'$a2===' => 'Exception',
'$y1===' => 'stdClass',
'$y2===' => 'Exception',
'$b1===' => 'stdClass',
'$b2===' => 'Exception',
'$e2===' => 'LogicException',
'$z1===' => 'stdClass',
'$z2===' => 'Exception',
'$x2===' => 'LogicException',
'$c1===' => "5",
'$c2===' => "'hello'",
'$d1===' => "5",
'$d2===' => "'hello'"
],
$context
);
}
/** @param array<string, string> $assertions */
private function assertContextVars(array $assertions, Context $context): void
{
$actual_vars = [];
foreach ($assertions as $var => $_) {
$exact = false;
if ($var && strpos($var, '===') === strlen($var) - 3) {
$var = substr($var, 0, -3);
$exact = true;
}
if (isset($context->vars_in_scope[$var])) {
$value = $context->vars_in_scope[$var]->getId($exact);
if ($exact) {
$actual_vars[$var . '==='] = $value;
} else {
$actual_vars[$var] = $value;
}
}
}
$this->assertSame($assertions, $actual_vars);
}
public function testNamespacedStubClass(): void

View File

@ -1,6 +1,7 @@
<?php
namespace PHPSTORM_META {
// tests with argument offset (0)
override(\Ns\MyClass::crEate(0), map([
'' => '@',
'exception' => \Exception::class,
@ -12,6 +13,18 @@ namespace PHPSTORM_META {
'object' => \stdClass::class,
]));
// tests without argument offset (0 by default)
override(\Ns\MyClass::crEate2(), map([
'' => '@',
'exception' => \Exception::class,
'object' => \stdClass::class,
]));
override(\create2(), map([
'' => '@',
'exception' => \Exception::class,
'object' => \stdClass::class,
]));
override(\Ns\MyClass::foO(0), type(0));
override(\Ns\MyClass::Bar(0), elementType(0));
override(\foo(0), type(0));