Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from Dec 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 20 additions & 6 deletions src/Psalm/Internal/Scanner/PhpStormMetaScanner.php
Expand Up @@ -89,15 +89,22 @@ public static function handleOverride(array $args, Codebase $codebase): void
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,
Expand Down Expand Up @@ -248,13 +255,20 @@ static function (

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,
Expand Down
74 changes: 74 additions & 0 deletions tests/StubTest.php
Expand Up @@ -22,6 +22,9 @@
use function getcwd;
use function implode;
use function reset;
use function strlen;
use function strpos;
use function substr;

use const DIRECTORY_SEPARATOR;

Expand Down Expand Up @@ -321,6 +324,12 @@ class MyClass {
*/
public function create(string $s) {}

/**
* @return mixed
* @psalm-suppress InvalidReturnType
*/
public function create2(string $s) {}

/**
* @param mixed $s
* @return mixed
Expand All @@ -342,6 +351,12 @@ public function bar(array $a) {}
*/
function create(string $s) {}

/**
* @return mixed
* @psalm-suppress InvalidReturnType
*/
function create2(string $s) {}

/**
* @param mixed $s
* @return mixed
Expand All @@ -358,11 +373,19 @@ function bar(array $a) {}
$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"]);

Expand All @@ -373,6 +396,57 @@ function bar(array $a) {}

$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
Expand Down
13 changes: 13 additions & 0 deletions tests/fixtures/stubs/phpstorm.meta.php
@@ -1,6 +1,7 @@
<?php
namespace PHPSTORM_META {

// tests with argument offset (0)
override(\Ns\MyClass::crEate(0), map([
'' => '@',
'exception' => \Exception::class,
Expand All @@ -12,6 +13,18 @@
'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));
Expand Down