From 160034e80f2ff7def66a47fa5531bc2cf7148812 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 2 Jun 2022 09:33:22 +0200 Subject: [PATCH] prepare parameter update --- .../PhpDocParser/BetterPhpDocParser.php | 4 +- .../ConstExprClassNameDecorator.php | 65 +++++++++++++++++++ .../Fixture/change_param_type.php.inc | 33 ++++++++++ .../Source/Gear.php | 12 ++++ .../Class_/ConstantListClassToEnumRector.php | 64 ++++++++++++++++-- 5 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 packages/BetterPhpDocParser/PhpDocParser/ConstExprClassNameDecorator.php create mode 100644 rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Fixture/change_param_type.php.inc create mode 100644 rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Source/Gear.php diff --git a/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php b/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php index 461427e2266..c00cb82e40f 100644 --- a/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php +++ b/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php @@ -32,7 +32,8 @@ public function __construct( TypeParser $typeParser, ConstExprParser $constExprParser, private readonly TokenIteratorFactory $tokenIteratorFactory, - private readonly DoctrineAnnotationDecorator $doctrineAnnotationDecorator + private readonly DoctrineAnnotationDecorator $doctrineAnnotationDecorator, + private readonly ConstExprClassNameDecorator $constExprClassNameDecorator, ) { parent::__construct($typeParser, $constExprParser); @@ -61,6 +62,7 @@ public function parse(TokenIterator $tokenIterator): PhpDocNode $phpDocNode = new PhpDocNode($children); // replace generic nodes with DoctrineAnnotations $this->doctrineAnnotationDecorator->decorate($phpDocNode); + $this->constExprClassNameDecorator->decorate($phpDocNode); return $phpDocNode; } diff --git a/packages/BetterPhpDocParser/PhpDocParser/ConstExprClassNameDecorator.php b/packages/BetterPhpDocParser/PhpDocParser/ConstExprClassNameDecorator.php new file mode 100644 index 00000000000..61585f00704 --- /dev/null +++ b/packages/BetterPhpDocParser/PhpDocParser/ConstExprClassNameDecorator.php @@ -0,0 +1,65 @@ +currentNodeProvider->getNode(); + + if (! $phpNode instanceof PhpNode) { + throw new ShouldNotHappenException(); + } + + $this->phpDocNodeTraverser->traverseWithCallable($phpDocNode, '', function (Node $node) use ( + $phpNode + ): int|Node|null { + if (! $node instanceof ConstExprNode) { + return null; + } + + $className = $this->resolveFullyQualifiedClass($node, $phpNode); + if ($className === null) { + return null; + } + + $node->setAttribute(PhpDocAttributeKey::RESOLVED_CLASS, $className); + return $node; + }); + } + + private function resolveFullyQualifiedClass(ConstExprNode $constExprNode, PhpNode $node): ?string + { + if (! $constExprNode instanceof ConstFetchNode) { + return null; + } + + $nameScope = $this->nameScopeFactory->createNameScopeFromNodeWithoutTemplateTypes($node); + return $nameScope->resolveStringName($constExprNode->className); + } +} diff --git a/rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Fixture/change_param_type.php.inc b/rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Fixture/change_param_type.php.inc new file mode 100644 index 00000000000..33669e3c40f --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Fixture/change_param_type.php.inc @@ -0,0 +1,33 @@ + +----- + + diff --git a/rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Source/Gear.php b/rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Source/Gear.php new file mode 100644 index 00000000000..37609b29c0f --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ConstantListClassToEnumRector/Source/Gear.php @@ -0,0 +1,12 @@ +enumConstListClassDetector->detect($node)) { + if ($node instanceof Class_) { + if (! $this->enumConstListClassDetector->detect($node)) { + return null; + } + + return $this->enumFactory->createFromClass($node); + } + + return $this->refactorClassMethod($node); + } + + private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod + { + if ($classMethod->params === []) { + return null; + } + + // enum param types doc requires a docblock + $phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod); + if (! $phpDocInfo instanceof PhpDocInfo) { return null; } - return $this->enumFactory->createFromClass($node); + $methodReflection = $this->reflectionResolver->resolveMethodReflectionFromClassMethod($classMethod); + + $parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants()); + foreach ($parametersAcceptor->getParameters() as $parameterReflection) { + if (! $parameterReflection instanceof PhpParameterReflection) { + continue; + } + + // should be union, that is how PHPStan resolves it + if (! $parameterReflection->getType() instanceof UnionType) { + continue; + } + + $paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName()); + if ($paramTagValueNode->type instanceof ConstTypeNode) { + $constTypeNode = $paramTagValueNode->type; + if ($constTypeNode->constExpr instanceof ConstFetchNode) { + $constExpr = $constTypeNode->constExpr; + dump($constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS)); + dump('___'); + die; + } + } + } + + return null; } }