Skip to content

Commit

Permalink
Type system: ConstantStringType created from ::class is always consid…
Browse files Browse the repository at this point in the history
…ered a classname
  • Loading branch information
ondrejmirtes committed Nov 11, 2021
1 parent 0319ace commit da34d3f
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 28 deletions.
7 changes: 2 additions & 5 deletions src/Type/ClassStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace PHPStan\Type;

use PHPStan\Reflection\ReflectionProviderStaticAccessor;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Constant\ConstantStringType;

Expand All @@ -28,8 +27,7 @@ public function accepts(Type $type, bool $strictTypes): TrinaryLogic
}

if ($type instanceof ConstantStringType) {
$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
return TrinaryLogic::createFromBoolean($reflectionProvider->hasClass($type->getValue()));
return TrinaryLogic::createFromBoolean($type->isClassString());
}

if ($type instanceof self) {
Expand All @@ -46,8 +44,7 @@ public function accepts(Type $type, bool $strictTypes): TrinaryLogic
public function isSuperTypeOf(Type $type): TrinaryLogic
{
if ($type instanceof ConstantStringType) {
$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
return TrinaryLogic::createFromBoolean($reflectionProvider->hasClass($type->getValue()));
return TrinaryLogic::createFromBoolean($type->isClassString());
}

if ($type instanceof self) {
Expand Down
12 changes: 8 additions & 4 deletions src/Type/Constant/ConstantStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ public function getValue(): string

public function isClassString(): bool
{
return $this->isClassString;
if ($this->isClassString) {
return true;
}

$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();

return $reflectionProvider->hasClass($this->value);
}

public function describe(VerbosityLevel $level): string
Expand Down Expand Up @@ -118,9 +124,7 @@ public function isSuperTypeOf(Type $type): TrinaryLogic
return TrinaryLogic::createNo();
}
if ($type instanceof ClassStringType) {
$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();

return $reflectionProvider->hasClass($this->getValue()) ? TrinaryLogic::createMaybe() : TrinaryLogic::createNo();
return $this->isClassString() ? TrinaryLogic::createMaybe() : TrinaryLogic::createNo();
}

if ($type instanceof self) {
Expand Down
4 changes: 1 addition & 3 deletions src/Type/Generic/GenericClassStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace PHPStan\Type\Generic;

use PHPStan\Reflection\ReflectionProviderStaticAccessor;
use PHPStan\TrinaryLogic;
use PHPStan\Type\ClassStringType;
use PHPStan\Type\CompoundType;
Expand Down Expand Up @@ -53,8 +52,7 @@ public function accepts(Type $type, bool $strictTypes): TrinaryLogic
}

if ($type instanceof ConstantStringType) {
$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
if (!$reflectionProvider->hasClass($type->getValue())) {
if (!$type->isClassString()) {
return TrinaryLogic::createNo();
}

Expand Down
26 changes: 10 additions & 16 deletions src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\FunctionTypeSpecifyingExtension;
use PHPStan\Type\NeverType;
use PHPStan\Type\TypeCombinator;

class ClassExistsFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension
{
Expand All @@ -41,20 +39,16 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
{
$argType = $scope->getType($node->getArgs()[0]->value);
$classStringType = new ClassStringType();
if (TypeCombinator::intersect($argType, $classStringType) instanceof NeverType) {
if ($argType instanceof ConstantStringType) {
return $this->typeSpecifier->create(
new FuncCall(new FullyQualified('class_exists'), [
new Arg(new String_(ltrim($argType->getValue(), '\\'))),
]),
new ConstantBooleanType(true),
$context,
false,
$scope
);
}

return new SpecifiedTypes();
if ($argType instanceof ConstantStringType) {
return $this->typeSpecifier->create(
new FuncCall(new FullyQualified('class_exists'), [
new Arg(new String_(ltrim($argType->getValue(), '\\'))),
]),
new ConstantBooleanType(true),
$context,
false,
$scope
);
}

return $this->typeSpecifier->create(
Expand Down
5 changes: 5 additions & 0 deletions tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -564,4 +564,9 @@ public function testBug5218(bool $checkExplicitMixed, array $errors): void
$this->analyse([__DIR__ . '/data/bug-5218.php'], $errors);
}

public function testBug5979(): void
{
$this->analyse([__DIR__ . '/data/bug-5979.php'], []);
}

}
31 changes: 31 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug-5979.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php declare(strict_types = 1);

namespace Bug5979;

class HelloWorld
{
/**
* @return list<array{string, class-string}>
*/
public function dataProviderForTestValidCommands(): array
{
$data = [
// left out some commands here for simplicity ...
// [...]
[
'migrations:execute',
SplQueue::class,
],
];

// this is only available with DBAL 2.x
if (class_exists(ImportCommand::class)) {
$data[] = [
'dbal:import',
ImportCommand::class,
];
}

return $data;
}
}

0 comments on commit da34d3f

Please sign in to comment.