mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 13:28:18 +01:00
update to phpstan 0.11.3
This commit is contained in:
parent
130be71958
commit
e1d988da3a
@ -11,7 +11,7 @@
|
||||
"nette/robot-loader": "^3.1",
|
||||
"nette/utils": "^2.5",
|
||||
"nikic/php-parser": "^4.2.1",
|
||||
"phpstan/phpstan": "^0.11.3",
|
||||
"phpstan/phpstan": "0.11.3",
|
||||
"sebastian/diff": "^3.0",
|
||||
"symfony/console": "^3.4|^4.2",
|
||||
"symfony/dependency-injection": "^3.4|^4.2",
|
||||
|
@ -175,18 +175,19 @@ final class NodeTypeResolver
|
||||
*/
|
||||
private function resolveFirstTypes(Node $node): array
|
||||
{
|
||||
// nodes that cannot be resolver by PHPStan
|
||||
$nodeClass = get_class($node);
|
||||
|
||||
if (isset($this->perNodeTypeResolvers[$nodeClass])) {
|
||||
return $this->perNodeTypeResolvers[$nodeClass]->resolve($node);
|
||||
}
|
||||
|
||||
/** @var Scope|null $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// nodes that cannot be resolver by PHPStan
|
||||
$nodeClass = get_class($node);
|
||||
if (isset($this->perNodeTypeResolvers[$nodeClass])) {
|
||||
return $this->perNodeTypeResolvers[$nodeClass]->resolve($node);
|
||||
}
|
||||
|
||||
if (! $node instanceof Expr) {
|
||||
return [];
|
||||
}
|
||||
@ -212,9 +213,9 @@ final class NodeTypeResolver
|
||||
$classTypes = $this->resolve($staticCall->class);
|
||||
$methodName = $this->nameResolver->resolve($staticCall->name);
|
||||
|
||||
// fallback
|
||||
// no specific method found, return class types, e.g. <ClassType>::$method()
|
||||
if (! is_string($methodName)) {
|
||||
return $this->resolve($staticCall->class);
|
||||
return $classTypes;
|
||||
}
|
||||
|
||||
foreach ($classTypes as $classType) {
|
||||
@ -222,14 +223,18 @@ final class NodeTypeResolver
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
/** @var Scope|null $nodeScope */
|
||||
$nodeScope = $staticCall->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
return $classTypes;
|
||||
}
|
||||
|
||||
$type = $nodeScope->getType($staticCall);
|
||||
if ($type instanceof ObjectType) {
|
||||
return [$type->getClassName()];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->resolve($staticCall->class);
|
||||
return $classTypes;
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,15 @@ namespace Rector\NodeTypeResolver\PHPStan\Scope;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PHPStan\Analyser\NodeScopeResolver as PHPStanNodeScopeResolver;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Broker\Broker;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\RemoveDeepChainMethodCallNodeVisitor;
|
||||
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
|
||||
|
||||
/**
|
||||
* @inspired by https://github.com/silverstripe/silverstripe-upgrader/blob/532182b23e854d02e0b27e68ebc394f436de0682/src/UpgradeRule/PHP/Visitor/PHPStanScopeVisitor.php
|
||||
@ -93,21 +94,27 @@ final class NodeScopeResolver
|
||||
* @param Class_|Interface_ $classOrInterfaceNode
|
||||
*/
|
||||
private function resolveClassOrInterfaceNode(Node $classOrInterfaceNode, Scope $scope): Scope
|
||||
{
|
||||
$className = $this->resolveClassName($classOrInterfaceNode);
|
||||
|
||||
$classReflection = $this->broker->getClass($className);
|
||||
|
||||
return $scope->enterClass($classReflection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Interface_ $classOrInterfaceNode
|
||||
*/
|
||||
private function resolveClassName(ClassLike $classOrInterfaceNode): string
|
||||
{
|
||||
if (isset($classOrInterfaceNode->namespacedName)) {
|
||||
return $scope->enterClass($this->broker->getClass((string) $classOrInterfaceNode->namespacedName));
|
||||
return (string) $classOrInterfaceNode->namespacedName;
|
||||
}
|
||||
|
||||
// possibly anonymous class
|
||||
$anonymousClassReflection = (new PrivatesAccessor())->getPrivateProperty(
|
||||
$this->phpStanNodeScopeResolver,
|
||||
'anonymousClassReflection'
|
||||
);
|
||||
|
||||
if ($anonymousClassReflection) {
|
||||
return $scope->enterAnonymousClass($anonymousClassReflection);
|
||||
if ($classOrInterfaceNode->name === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return $scope;
|
||||
return $classOrInterfaceNode->name->toString();
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\Reflection\ClassReflectionTypesResolver;
|
||||
@ -38,10 +37,8 @@ final class ClassAndInterfaceTypeResolver implements PerNodeTypeResolverInterfac
|
||||
*/
|
||||
public function resolve(Node $node): array
|
||||
{
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
/** @var ClassReflection $classReflection */
|
||||
$classReflection = $nodeScope->getClassReflection();
|
||||
|
@ -3,8 +3,12 @@
|
||||
namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Param;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
|
||||
final class ParamTypeResolver implements PerNodeTypeResolverInterface
|
||||
@ -14,9 +18,15 @@ final class ParamTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
public function __construct(NameResolver $nameResolver)
|
||||
/**
|
||||
* @var DocBlockManipulator
|
||||
*/
|
||||
private $docBlockManipulator;
|
||||
|
||||
public function __construct(NameResolver $nameResolver, DocBlockManipulator $docBlockManipulator)
|
||||
{
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->docBlockManipulator = $docBlockManipulator;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,15 +43,38 @@ final class ParamTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
public function resolve(Node $paramNode): array
|
||||
{
|
||||
if ($paramNode->type === null) {
|
||||
if ($paramNode->type) {
|
||||
$resolveTypeName = $this->nameResolver->resolve($paramNode->type);
|
||||
if ($resolveTypeName) {
|
||||
return [$resolveTypeName];
|
||||
}
|
||||
}
|
||||
|
||||
/** @var FunctionLike $parentNode */
|
||||
$parentNode = $paramNode->getAttribute(Attribute::PARENT_NODE);
|
||||
|
||||
return $this->resolveTypesFromFunctionDocBlock($paramNode, $parentNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveTypesFromFunctionDocBlock(Param $param, FunctionLike $functionLike): array
|
||||
{
|
||||
$paramTypeInfos = $this->docBlockManipulator->getParamTypeInfos($functionLike);
|
||||
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->nameResolver->resolve($param->var);
|
||||
if (! isset($paramTypeInfos[$paramName])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$resolveTypeName = $this->nameResolver->resolve($paramNode->type);
|
||||
if ($resolveTypeName) {
|
||||
return [$resolveTypeName];
|
||||
$fqnTypeNode = $paramTypeInfos[$paramName]->getFqnTypeNode();
|
||||
|
||||
if ($fqnTypeNode instanceof NullableType) {
|
||||
return ['null', (string) $fqnTypeNode->type];
|
||||
}
|
||||
|
||||
return [];
|
||||
return [(string) $fqnTypeNode];
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,19 @@ namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type\ThisType;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Contract\NodeTypeResolverAwareInterface;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeToStringResolver;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
|
||||
final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
final class VariableTypeResolver implements PerNodeTypeResolverInterface, NodeTypeResolverAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var DocBlockManipulator
|
||||
@ -31,6 +33,11 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
public function __construct(
|
||||
DocBlockManipulator $docBlockManipulator,
|
||||
TypeToStringResolver $typeToStringResolver,
|
||||
@ -55,9 +62,9 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
public function resolve(Node $variableNode): array
|
||||
{
|
||||
$nodeScope = $variableNode->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
$parentNode = $variableNode->getAttribute(Attribute::PARENT_NODE);
|
||||
if ($parentNode instanceof Param) {
|
||||
return $this->nodeTypeResolver->resolve($parentNode);
|
||||
}
|
||||
|
||||
$variableName = $this->nameResolver->resolve($variableNode);
|
||||
@ -65,15 +72,9 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($nodeScope->hasVariableType($variableName) === TrinaryLogic::createYes()) {
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
|
||||
// this
|
||||
if ($type instanceof ThisType) {
|
||||
return [$nodeScope->getClassReflection()->getName()];
|
||||
}
|
||||
|
||||
return $this->typeToStringResolver->resolve($type);
|
||||
$scopeType = $this->resolveTypesFromScope($variableNode, $variableName);
|
||||
if ($scopeType !== []) {
|
||||
return $scopeType;
|
||||
}
|
||||
|
||||
// get from annotation
|
||||
@ -83,10 +84,65 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
}
|
||||
|
||||
$varType = $varTypeInfo->getFqnType();
|
||||
if ($varType === null) {
|
||||
|
||||
return $varType === null ? [] : [$varType];
|
||||
}
|
||||
|
||||
public function setNodeTypeResolver(NodeTypeResolver $nodeTypeResolver): void
|
||||
{
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
private function resolveNodeScope(Node $variableNode): ?Scope
|
||||
{
|
||||
/** @var Scope|null $nodeScope */
|
||||
$nodeScope = $variableNode->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope instanceof Scope) {
|
||||
return $nodeScope;
|
||||
}
|
||||
|
||||
$parentNode = $variableNode->getAttribute(Attribute::PARENT_NODE);
|
||||
if ($parentNode instanceof Node) {
|
||||
$nodeScope = $parentNode->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope instanceof Scope) {
|
||||
return $nodeScope;
|
||||
}
|
||||
}
|
||||
|
||||
// get nearest variable scope
|
||||
$method = $variableNode->getAttribute(Attribute::METHOD_NODE);
|
||||
if ($method instanceof Node) {
|
||||
$nodeScope = $method->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope instanceof Scope) {
|
||||
return $nodeScope;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown scope
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveTypesFromScope(Variable $variable, string $variableName): array
|
||||
{
|
||||
$nodeScope = $this->resolveNodeScope($variable);
|
||||
if ($nodeScope === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [$varType];
|
||||
if ($nodeScope->hasVariableType($variableName) !== TrinaryLogic::createYes()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
|
||||
// this
|
||||
if ($type instanceof ThisType) {
|
||||
return [$nodeScope->getClassReflection()->getName()];
|
||||
}
|
||||
|
||||
return $this->typeToStringResolver->resolve($type);
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ final class DocBlockManipulator
|
||||
|
||||
$phpDocInfo = $this->createPhpDocInfoFromNode($node);
|
||||
$types = $phpDocInfo->getParamTagValues();
|
||||
|
||||
if ($types === []) {
|
||||
return [];
|
||||
}
|
||||
@ -193,7 +194,7 @@ final class DocBlockManipulator
|
||||
$paramTagValueNode->parameterName,
|
||||
$this->typeAnalyzer,
|
||||
$paramTagValueNode->getAttribute(Attribute::TYPE_AS_ARRAY),
|
||||
$fqnParamTagValueNode->getAttribute(Attribute::TYPE_AS_ARRAY)
|
||||
$fqnParamTagValueNode->getAttribute(Attribute::RESOLVED_NAMES)
|
||||
);
|
||||
|
||||
$paramTypeInfos[$paramTypeInfo->getName()] = $paramTypeInfo;
|
||||
|
@ -78,7 +78,7 @@ CODE_SAMPLE
|
||||
unset($node->stmts[$key]);
|
||||
}
|
||||
|
||||
$node->stmts = array_merge($node->stmts, $proccesed);
|
||||
$node->stmts = array_merge($node->stmts, (array) $proccesed);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\Node\Stmt\PropertyProperty;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use PHPStan\Type\ErrorType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
@ -26,8 +27,6 @@ use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* This depends on the context. We need more real app datas.
|
||||
*
|
||||
* @see https://3v4l.org/ABDNv
|
||||
* @see https://stackoverflow.com/a/41000866/1348344
|
||||
*/
|
||||
@ -139,7 +138,7 @@ CODE_SAMPLE
|
||||
private function processProperty(Node $propertyNode): bool
|
||||
{
|
||||
foreach ($this->emptyStringPropertyNodes as $emptyStringPropertyNode) {
|
||||
if ($this->getName($emptyStringPropertyNode) === $this->getName($propertyNode)) {
|
||||
if ($this->areNamesEqual($emptyStringPropertyNode, $propertyNode)) {
|
||||
$emptyStringPropertyNode->default = new Array_();
|
||||
|
||||
return true;
|
||||
@ -187,6 +186,10 @@ CODE_SAMPLE
|
||||
|
||||
private function shouldSkipVariable(?Type $staticType): bool
|
||||
{
|
||||
if ($staticType instanceof ErrorType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($staticType instanceof UnionType) {
|
||||
return ! ($staticType->isSuperTypeOf(new ArrayType(new MixedType(), new MixedType()))->yes() &&
|
||||
$staticType->isSuperTypeOf(new ConstantStringType(''))->yes());
|
||||
|
Loading…
x
Reference in New Issue
Block a user