Skip to content

Commit

Permalink
Fix calling method statically on string
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 18, 2022
1 parent ab0245c commit 3aa878f
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 4 deletions.
19 changes: 15 additions & 4 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -2235,10 +2235,21 @@ private function resolveType(Expr $node): Type
if ($node->class instanceof Name) {
$staticMethodCalledOnType = $this->resolveTypeByName($node->class);
} else {
$staticMethodCalledOnType = $this->getType($node->class);
if ($staticMethodCalledOnType instanceof GenericClassStringType) {
$staticMethodCalledOnType = $staticMethodCalledOnType->getGenericType();
}
$staticMethodCalledOnType = TypeTraverser::map($this->getType($node->class), static function (Type $type, callable $traverse): Type {
if ($type instanceof UnionType) {
return $traverse($type);
}

if ($type instanceof GenericClassStringType) {
return $type->getGenericType();
}

if ($type instanceof ConstantStringType && $type->isClassString()) {
return new ObjectType($type->getValue());
}

return $type;
});
}

$returnType = $this->methodCallReturnType(
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ public function dataFileAsserts(): iterable

yield from $this->gatherAssertTypes(__DIR__ . '/data/weird-array_key_exists-issue.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/equal.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6404.php');
}

/**
Expand Down
85 changes: 85 additions & 0 deletions tests/PHPStan/Analyser/data/bug-6404.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Bug6404;


use function PHPStan\Testing\assertType;

class Foo
{
public static function getCode(): int
{
return 1;
}
}

class Bar
{
private const FOOS = [
Foo::class,
];

/**
* @var array<int, bool>
*/
private array $someMap = [];

public function build(): void
{
foreach (self::FOOS as $fooClass) {
if (is_a($fooClass, Foo::class, true)) {
assertType("'Bug6404\\\\Foo'", $fooClass);
assertType('int', $fooClass::getCode());
$this->someMap[$fooClass::getCode()] = true;
}
}
}

/**
* @param object[] $objects
* @return void
*/
public function build2(array $objects): void
{
foreach ($objects as $fooClass) {
if (is_a($fooClass, Foo::class)) {
assertType(Foo::class, $fooClass);
assertType('int', $fooClass::getCode());
$this->someMap[$fooClass::getCode()] = true;
}
}
}

/**
* @param mixed[] $mixeds
* @return void
*/
public function build3(array $mixeds): void
{
foreach ($mixeds as $fooClass) {
if (is_a($fooClass, Foo::class, true)) {
assertType('Bug6404\\Foo|class-string<Bug6404\\Foo>', $fooClass);
assertType('int', $fooClass::getCode());
$this->someMap[$fooClass::getCode()] = true;
}
}
}

/**
* @param class-string<Foo> $classString
* @return void
*/
public function doBar(string $classString): void
{
assertType("class-string<" . Foo::class . ">", $classString);
assertType('int', $classString::getCode());
}

/**
* @return array<int, bool>
*/
public function getAll(): array
{
return $this->someMap;
}
}

0 comments on commit 3aa878f

Please sign in to comment.