rector/vendor/symplify/astral/src/NodeValue/NodeValueResolver.php
Tomas Votruba dd1c4722cb Updated Rector to commit af0fc79863
af0fc79863 Fix preload.php order to included firstly used classes first, to avoid missing parent bugs (#929)
2021-09-28 16:17:28 +00:00

178 lines
6.7 KiB
PHP

<?php
declare (strict_types=1);
namespace RectorPrefix20210928\Symplify\Astral\NodeValue;
use PhpParser\ConstExprEvaluationException;
use PhpParser\ConstExprEvaluator;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Instanceof_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\MagicConst;
use PhpParser\Node\Scalar\MagicConst\Dir;
use PhpParser\Node\Scalar\MagicConst\File;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\Scope;
use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\UnionType;
use ReflectionClassConstant;
use RectorPrefix20210928\Symplify\Astral\Exception\ShouldNotHappenException;
use RectorPrefix20210928\Symplify\Astral\Naming\SimpleNameResolver;
use RectorPrefix20210928\Symplify\Astral\NodeFinder\SimpleNodeFinder;
use RectorPrefix20210928\Symplify\PackageBuilder\Php\TypeChecker;
/**
* @see \Symplify\Astral\Tests\NodeValue\NodeValueResolverTest
*/
final class NodeValueResolver
{
/**
* @var \PhpParser\ConstExprEvaluator
*/
private $constExprEvaluator;
/**
* @var string|null
*/
private $currentFilePath;
/**
* @var \Symplify\Astral\NodeValue\UnionTypeValueResolver
*/
private $unionTypeValueResolver;
/**
* @var \Symplify\Astral\Naming\SimpleNameResolver
*/
private $simpleNameResolver;
/**
* @var \Symplify\PackageBuilder\Php\TypeChecker
*/
private $typeChecker;
/**
* @var \Symplify\Astral\NodeFinder\SimpleNodeFinder
*/
private $simpleNodeFinder;
public function __construct(\RectorPrefix20210928\Symplify\Astral\Naming\SimpleNameResolver $simpleNameResolver, \RectorPrefix20210928\Symplify\PackageBuilder\Php\TypeChecker $typeChecker, \RectorPrefix20210928\Symplify\Astral\NodeFinder\SimpleNodeFinder $simpleNodeFinder)
{
$this->simpleNameResolver = $simpleNameResolver;
$this->typeChecker = $typeChecker;
$this->simpleNodeFinder = $simpleNodeFinder;
$this->constExprEvaluator = new \PhpParser\ConstExprEvaluator(function (\PhpParser\Node\Expr $expr) {
return $this->resolveByNode($expr);
});
$this->unionTypeValueResolver = new \RectorPrefix20210928\Symplify\Astral\NodeValue\UnionTypeValueResolver();
}
/**
* @return array|bool|float|int|mixed|string|null
*/
public function resolveWithScope(\PhpParser\Node\Expr $expr, \PHPStan\Analyser\Scope $scope)
{
$this->currentFilePath = $scope->getFile();
try {
return $this->constExprEvaluator->evaluateDirectly($expr);
} catch (\PhpParser\ConstExprEvaluationException $exception) {
}
$exprType = $scope->getType($expr);
if ($exprType instanceof \PHPStan\Type\ConstantScalarType) {
return $exprType->getValue();
}
if ($exprType instanceof \PHPStan\Type\UnionType) {
return $this->unionTypeValueResolver->resolveConstantTypes($exprType);
}
return null;
}
/**
* @return array|bool|float|int|mixed|string|null
*/
public function resolve(\PhpParser\Node\Expr $expr, string $filePath)
{
$this->currentFilePath = $filePath;
try {
return $this->constExprEvaluator->evaluateDirectly($expr);
} catch (\PhpParser\ConstExprEvaluationException $exception) {
return null;
}
}
/**
* @return mixed|null
*/
private function resolveClassConstFetch(\PhpParser\Node\Expr\ClassConstFetch $classConstFetch)
{
$className = $this->simpleNameResolver->getName($classConstFetch->class);
if ($className === 'self') {
$classLike = $this->simpleNodeFinder->findFirstParentByType($classConstFetch, \PhpParser\Node\Stmt\ClassLike::class);
if (!$classLike instanceof \PhpParser\Node\Stmt\ClassLike) {
return null;
}
$className = $this->simpleNameResolver->getName($classLike);
}
if ($className === null) {
return null;
}
$constantName = $this->simpleNameResolver->getName($classConstFetch->name);
if ($constantName === null) {
return null;
}
if ($constantName === 'class') {
return $className;
}
if (!\class_exists($className) && !\interface_exists($className)) {
return null;
}
$reflectionClassConstant = new \ReflectionClassConstant($className, $constantName);
return $reflectionClassConstant->getValue();
}
private function resolveMagicConst(\PhpParser\Node\Scalar\MagicConst $magicConst) : ?string
{
if ($this->currentFilePath === null) {
throw new \RectorPrefix20210928\Symplify\Astral\Exception\ShouldNotHappenException();
}
if ($magicConst instanceof \PhpParser\Node\Scalar\MagicConst\Dir) {
return \dirname($this->currentFilePath);
}
if ($magicConst instanceof \PhpParser\Node\Scalar\MagicConst\File) {
return $this->currentFilePath;
}
return null;
}
/**
* @return mixed|null
*/
private function resolveConstFetch(\PhpParser\Node\Expr\ConstFetch $constFetch)
{
$constFetchName = $this->simpleNameResolver->getName($constFetch);
if ($constFetchName === null) {
return null;
}
return \constant($constFetchName);
}
/**
* @return mixed|string|int|bool|null
*/
private function resolveByNode(\PhpParser\Node\Expr $expr)
{
if ($this->currentFilePath === null) {
throw new \RectorPrefix20210928\Symplify\Astral\Exception\ShouldNotHappenException();
}
if ($expr instanceof \PhpParser\Node\Scalar\MagicConst) {
return $this->resolveMagicConst($expr);
}
if ($expr instanceof \PhpParser\Node\Expr\FuncCall && $this->simpleNameResolver->isName($expr, 'getcwd')) {
return \dirname($this->currentFilePath);
}
if ($expr instanceof \PhpParser\Node\Expr\ConstFetch) {
return $this->resolveConstFetch($expr);
}
if ($expr instanceof \PhpParser\Node\Expr\ClassConstFetch) {
return $this->resolveClassConstFetch($expr);
}
if ($this->typeChecker->isInstanceOf($expr, [\PhpParser\Node\Expr\Variable::class, \PhpParser\Node\Expr\Cast::class, \PhpParser\Node\Expr\MethodCall::class, \PhpParser\Node\Expr\PropertyFetch::class, \PhpParser\Node\Expr\Instanceof_::class])) {
throw new \PhpParser\ConstExprEvaluationException();
}
return null;
}
}