update to phpstan 0.11.3

This commit is contained in:
Tomas Votruba 2019-03-10 23:47:43 +00:00
parent 130be71958
commit e1d988da3a
9 changed files with 155 additions and 53 deletions

View File

@ -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",

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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];
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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());