From ca3f502aa15faf7c2d73e8e2de956a6f5259c92f Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 10 Feb 2020 01:42:15 +0100 Subject: [PATCH] decopule PropertyFetchTypeResolver --- ...ableThisArrayToAnonymousFunctionRector.php | 1 - .../src/NodeTypeResolver.php | 84 ---------- .../PropertyFetchTypeResolver.php | 146 ++++++++++++++++++ .../Fixture/symfony_console_command.php.inc | 2 +- 4 files changed, 147 insertions(+), 86 deletions(-) create mode 100644 packages/node-type-resolver/src/PerNodeTypeResolver/PropertyFetchTypeResolver.php diff --git a/packages/code-quality/src/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php b/packages/code-quality/src/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php index 1e573849f93d..453f783c866a 100644 --- a/packages/code-quality/src/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php +++ b/packages/code-quality/src/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php @@ -145,7 +145,6 @@ private function matchCallableMethod(Expr $objectExpr, String_ $methodExpr): ?Cl } $objectType = $this->getObjectType($objectExpr); - if ($objectType instanceof ObjectType) { $class = $this->classLikeParsedNodesFinder->findClass($objectType->getClassName()); diff --git a/packages/node-type-resolver/src/NodeTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver.php index c1e2489f5f5e..06dc13687e15 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver.php @@ -10,13 +10,10 @@ use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Param; use PhpParser\Node\Scalar; use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\Nop; use PHPStan\Analyser\Scope; -use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ArrayType; use PHPStan\Type\FloatType; @@ -29,9 +26,7 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; -use Rector\BetterPhpDocParser\PhpDocParser\BetterPhpDocParser; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\Core\NodeContainer\NodeCollector\ParsedNodeCollector; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -39,7 +34,6 @@ use Rector\NodeTypeResolver\Reflection\ClassReflectionTypesResolver; use Rector\NodeTypeResolver\TypeAnalyzer\ArrayTypeAnalyzer; use Rector\TypeDeclaration\PHPStan\Type\ObjectTypeSpecifier; -use ReflectionProperty; final class NodeTypeResolver { @@ -73,21 +67,6 @@ final class NodeTypeResolver */ private $objectTypeSpecifier; - /** - * @var ParsedNodeCollector - */ - private $parsedNodeCollector; - - /** - * @var BetterPhpDocParser - */ - private $betterPhpDocParser; - - /** - * @var StaticTypeMapper - */ - private $staticTypeMapper; - /** * @var ArrayTypeAnalyzer */ @@ -97,13 +76,10 @@ final class NodeTypeResolver * @param PerNodeTypeResolverInterface[] $perNodeTypeResolvers */ public function __construct( - BetterPhpDocParser $betterPhpDocParser, NodeNameResolver $nodeNameResolver, - ParsedNodeCollector $parsedNodeCollector, ClassReflectionTypesResolver $classReflectionTypesResolver, ReflectionProvider $reflectionProvider, TypeFactory $typeFactory, - StaticTypeMapper $staticTypeMapper, ObjectTypeSpecifier $objectTypeSpecifier, array $perNodeTypeResolvers ) { @@ -117,9 +93,6 @@ public function __construct( $this->reflectionProvider = $reflectionProvider; $this->typeFactory = $typeFactory; $this->objectTypeSpecifier = $objectTypeSpecifier; - $this->parsedNodeCollector = $parsedNodeCollector; - $this->betterPhpDocParser = $betterPhpDocParser; - $this->staticTypeMapper = $staticTypeMapper; } /** @@ -218,10 +191,6 @@ public function getStaticType(Node $node): Type return $staticType; } - if ($node instanceof PropertyFetch) { - return $this->resolvePropertyFetchType($node); - } - return $this->objectTypeSpecifier->narrowToFullyQualifiedOrAlaisedObjectType($node, $staticType); } @@ -401,48 +370,6 @@ private function isAnonymousClass(Node $node): bool return $className === null || Strings::contains($className, 'AnonymousClass'); } - private function getVendorPropertyFetchType(PropertyFetch $propertyFetch): ?Type - { - $varObjectType = $this->resolve($propertyFetch->var); - if (! $varObjectType instanceof TypeWithClassName) { - return null; - } - - if ($this->parsedNodeCollector->findClass($varObjectType->getClassName()) !== null) { - return null; - } - - // 3rd party code - $propertyName = $this->nodeNameResolver->getName($propertyFetch->name); - if ($propertyName === null) { - return null; - } - - if (! property_exists($varObjectType->getClassName(), $propertyName)) { - return null; - } - - // property is used - $propertyReflection = new ReflectionProperty($varObjectType->getClassName(), $propertyName); - if (! $propertyReflection->getDocComment()) { - return null; - } - - $phpDocNode = $this->betterPhpDocParser->parseString((string) $propertyReflection->getDocComment()); - $varTagValues = $phpDocNode->getVarTagValues(); - - if (! isset($varTagValues[0])) { - return null; - } - - $typeNode = $varTagValues[0]->type; - if (! $typeNode instanceof TypeNode) { - return null; - } - - return $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode, new Nop()); - } - /** * @return string[] */ @@ -470,15 +397,4 @@ private function isMatchingUnionType(Type $requiredType, Type $resolvedType): bo return false; } - - private function resolvePropertyFetchType(PropertyFetch $propertyFetch) - { - // compensate 3rd party non-analysed property reflection - $vendorPropertyType = $this->getVendorPropertyFetchType($propertyFetch); - if ($vendorPropertyType !== null) { - return $vendorPropertyType; - } - - return new MixedType(); - } } diff --git a/packages/node-type-resolver/src/PerNodeTypeResolver/PropertyFetchTypeResolver.php b/packages/node-type-resolver/src/PerNodeTypeResolver/PropertyFetchTypeResolver.php new file mode 100644 index 000000000000..0241a7d9d6e2 --- /dev/null +++ b/packages/node-type-resolver/src/PerNodeTypeResolver/PropertyFetchTypeResolver.php @@ -0,0 +1,146 @@ +parsedNodeCollector = $parsedNodeCollector; + $this->nodeNameResolver = $nodeNameResolver; + $this->betterPhpDocParser = $betterPhpDocParser; + $this->staticTypeMapper = $staticTypeMapper; + } + + /** + * @required + */ + public function autowirePropertyTypeResolver(NodeTypeResolver $nodeTypeResolver): void + { + $this->nodeTypeResolver = $nodeTypeResolver; + } + + /** + * @return string[] + */ + public function getNodeClasses(): array + { + return [PropertyFetch::class]; + } + + /** + * @param PropertyFetch $node + */ + public function resolve(Node $node): Type + { + // compensate 3rd party non-analysed property reflection + $vendorPropertyType = $this->getVendorPropertyFetchType($node); + if ($vendorPropertyType !== null) { + return $vendorPropertyType; + } + + /** @var Scope|null $scope */ + $scope = $node->getAttribute(AttributeKey::SCOPE); + if ($scope === null) { + return new MixedType(); + } + + return $scope->getType($node); + } + + private function getVendorPropertyFetchType(PropertyFetch $propertyFetch): ?Type + { + $varObjectType = $this->nodeTypeResolver->resolve($propertyFetch->var); + + if (! $varObjectType instanceof TypeWithClassName) { + return null; + } + + $class = $this->parsedNodeCollector->findClass($varObjectType->getClassName()); + if ($class !== null) { + return null; + } + + // 3rd party code + $propertyName = $this->nodeNameResolver->getName($propertyFetch->name); + if ($propertyName === null) { + return null; + } + + if (! property_exists($varObjectType->getClassName(), $propertyName)) { + return null; + } + + // property is used + $propertyReflection = new ReflectionProperty($varObjectType->getClassName(), $propertyName); + if (! $propertyReflection->getDocComment()) { + return null; + } + + $phpDocNode = $this->betterPhpDocParser->parseString((string) $propertyReflection->getDocComment()); + $varTagValues = $phpDocNode->getVarTagValues(); + + if (! isset($varTagValues[0])) { + return null; + } + + $typeNode = $varTagValues[0]->type; + if (! $typeNode instanceof TypeNode) { + return null; + } + + return $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode, new Nop()); + } +} diff --git a/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc b/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc index 7687984b57b3..57e8b8c6b66f 100644 --- a/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc +++ b/packages/type-declaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Fixture/symfony_console_command.php.inc @@ -595,7 +595,7 @@ class Command */ private $processTitle; /** - * @var InputDefinition + * @var \Symfony\Component\Console\Input\InputDefinition */ private $definition; /**