forked from phpstan/phpstan-src
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add return type extension for
constant()
- Loading branch information
1 parent
a540e44
commit be378e1
Showing
6 changed files
with
136 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Type\Php; | ||
|
||
use PhpParser\Node\Expr\FuncCall; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Reflection\FunctionReflection; | ||
use PHPStan\Type\DynamicFunctionReturnTypeExtension; | ||
use PHPStan\Type\Type; | ||
use PHPStan\Type\TypeCombinator; | ||
use function count; | ||
|
||
class ConstantFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension | ||
{ | ||
|
||
public function __construct(private ConstantHelper $constantHelper) | ||
{ | ||
} | ||
|
||
public function isFunctionSupported(FunctionReflection $functionReflection): bool | ||
{ | ||
return $functionReflection->getName() === 'constant'; | ||
} | ||
|
||
public function getTypeFromFunctionCall( | ||
FunctionReflection $functionReflection, | ||
FuncCall $functionCall, | ||
Scope $scope, | ||
): ?Type | ||
{ | ||
if (count($functionCall->getArgs()) < 1) { | ||
return null; | ||
} | ||
|
||
$nameType = $scope->getType($functionCall->getArgs()[0]->value); | ||
|
||
$results = []; | ||
foreach ($nameType->getConstantStrings() as $constantName) { | ||
$results[] = $scope->getType($this->constantHelper->createExprFromConstantName($constantName->getValue())); | ||
} | ||
|
||
if (count($results) > 0) { | ||
return TypeCombinator::union(...$results); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Type\Php; | ||
|
||
use PhpParser\Node\Expr; | ||
use PhpParser\Node\Expr\ClassConstFetch; | ||
use PhpParser\Node\Expr\ConstFetch; | ||
use PhpParser\Node\Identifier; | ||
use PhpParser\Node\Name; | ||
use PhpParser\Node\Name\FullyQualified; | ||
use function count; | ||
use function explode; | ||
use function ltrim; | ||
|
||
class ConstantHelper | ||
{ | ||
|
||
public function createExprFromConstantName(string $constantName): Expr | ||
{ | ||
$classConstParts = explode('::', $constantName); | ||
if (count($classConstParts) >= 2) { | ||
$classConstName = new FullyQualified(ltrim($classConstParts[0], '\\')); | ||
if ($classConstName->isSpecialClassName()) { | ||
$classConstName = new Name($classConstName->toString()); | ||
} | ||
|
||
return new ClassConstFetch($classConstName, new Identifier($classConstParts[1])); | ||
} | ||
|
||
return new ConstFetch(new FullyQualified($constantName)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php // lint >= 8.1 | ||
|
||
namespace Constant; | ||
|
||
use function PHPStan\Testing\assertType; | ||
|
||
define('FOO', 'foo'); | ||
const BAR = 'bar'; | ||
|
||
class Baz | ||
{ | ||
const BAZ = 'baz'; | ||
} | ||
|
||
enum Suit | ||
{ | ||
case Hearts; | ||
} | ||
|
||
function doFoo(string $constantName): void | ||
{ | ||
assertType('mixed', constant($constantName)); | ||
} | ||
|
||
assertType("'foo'", FOO); | ||
assertType("'foo'", constant('FOO')); | ||
assertType("*ERROR*", constant('\Constant\FOO')); | ||
|
||
assertType("'bar'", BAR); | ||
assertType("*ERROR*", constant('BAR')); | ||
assertType("'bar'", constant('\Constant\BAR')); | ||
|
||
assertType("'bar'|'foo'", constant(rand(0, 1) ? 'FOO' : '\Constant\BAR')); | ||
|
||
assertType("'baz'", constant('\Constant\Baz::BAZ')); | ||
|
||
assertType('Constant\Suit::Hearts', Suit::Hearts); | ||
assertType('Constant\Suit::Hearts', constant('\Constant\Suit::Hearts')); | ||
|
||
assertType('*ERROR*', constant('UNDEFINED')); |