Skip to content

Commit

Permalink
prepare parameter update
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jun 2, 2022
1 parent c7871e1 commit 160034e
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Rector\BetterPhpDocParser\PhpDocParser;

use PhpParser\Node as PhpNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\StaticTypeMapper\Naming\NameScopeFactory;
use Symplify\Astral\PhpDocParser\PhpDocNodeTraverser;

/**
* Decorate node with fully qualified class name for const epxr,
* e.g. Direction::*
*/
final class ConstExprClassNameDecorator
{
public function __construct(
private CurrentNodeProvider $currentNodeProvider,
private NameScopeFactory $nameScopeFactory,
private PhpDocNodeTraverser $phpDocNodeTraverser
) {
}

public function decorate(PhpDocNode $phpDocNode): void
{
$phpNode = $this->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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Fixture;

use Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear;

final class ChangeParamType
{
/**
* @param Gear::* $gear
*/
public function changeGear(string $gear)
{
}
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Fixture;

use Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear;

final class ChangeParamType
{
public function changeGear(Gear $gear)
{
}
}

?>

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source;

final class Gear
{
public const FIRST = 'first';

public const SECOND = 'second';
}
64 changes: 59 additions & 5 deletions rules/Php80/Rector/Class_/ConstantListClassToEnumRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\Php\PhpParameterReflection;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Php80\NodeAnalyzer\EnumConstListClassDetector;
use Rector\Php81\NodeFactory\EnumFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
Expand All @@ -19,7 +28,8 @@ final class ConstantListClassToEnumRector extends AbstractRector
{
public function __construct(
private readonly EnumConstListClassDetector $enumConstListClassDetector,
private readonly EnumFactory $enumFactory
private readonly EnumFactory $enumFactory,
private readonly ReflectionResolver $reflectionResolver,
) {
}

Expand Down Expand Up @@ -54,18 +64,62 @@ enum Direction
*/
public function getNodeTypes(): array
{
return [Class_::class];
return [Class_::class, ClassMethod::class];
}

/**
* @param Class_ $node
* @param Class_|ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->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;
}
}

0 comments on commit 160034e

Please sign in to comment.