Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PHP 8.0] Add method param to ConstantListClassToEnumRector #2415

Merged
merged 4 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions easy-ci.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use PHPStan\PhpDocParser\Parser\TypeParser;
use Rector\BetterPhpDocParser\Contract\PhpDocParser\PhpDocNodeDecoratorInterface;
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
Expand Down Expand Up @@ -40,6 +41,7 @@
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_SKIP, [
PhpDocNodeDecoratorInterface::class,
Command::class,
Application::class,
RectorInterface::class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Rector\BetterPhpDocParser\Contract\PhpDocParser;

use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;

interface PhpDocNodeDecoratorInterface
{
public function decorate(PhpDocNode $phpDocNode, Node $phpNode): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __construct(
private readonly StaticTypeMapper $staticTypeMapper,
private readonly AnnotationNaming $annotationNaming,
private readonly RectorChangeCollector $rectorChangeCollector,
private readonly PhpDocNodeByTypeFinder $phpDocNodeByTypeFinder
private readonly PhpDocNodeByTypeFinder $phpDocNodeByTypeFinder,
) {
}

Expand Down
27 changes: 20 additions & 7 deletions packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rector\BetterPhpDocParser\PhpDocParser;

use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
Expand All @@ -14,10 +15,12 @@
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use Rector\BetterPhpDocParser\Contract\PhpDocParser\PhpDocNodeDecoratorInterface;
use Rector\BetterPhpDocParser\PhpDocInfo\TokenIteratorFactory;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\BetterPhpDocParser\ValueObject\StartAndEnd;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Symplify\PackageBuilder\Reflection\PrivatesCaller;

Expand All @@ -26,17 +29,18 @@
*/
final class BetterPhpDocParser extends PhpDocParser
{
private readonly PrivatesCaller $privatesCaller;

/**
* @param PhpDocNodeDecoratorInterface[] $phpDocNodeDecorators
*/
public function __construct(
TypeParser $typeParser,
ConstExprParser $constExprParser,
private readonly CurrentNodeProvider $currentNodeProvider,
private readonly TokenIteratorFactory $tokenIteratorFactory,
private readonly DoctrineAnnotationDecorator $doctrineAnnotationDecorator
private readonly array $phpDocNodeDecorators,
private readonly PrivatesCaller $privatesCaller = new PrivatesCaller(),
) {
parent::__construct($typeParser, $constExprParser);

$this->privatesCaller = new PrivatesCaller();
}

public function parse(TokenIterator $tokenIterator): PhpDocNode
Expand All @@ -59,14 +63,23 @@ public function parse(TokenIterator $tokenIterator): PhpDocNode
$tokenIterator->tryConsumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC);

$phpDocNode = new PhpDocNode($children);
// replace generic nodes with DoctrineAnnotations
$this->doctrineAnnotationDecorator->decorate($phpDocNode);

// decorate FQN classes etc.
$node = $this->currentNodeProvider->getNode();
if (! $node instanceof Node) {
throw new ShouldNotHappenException();
}

foreach ($this->phpDocNodeDecorators as $phpDocNodeDecorator) {
$phpDocNodeDecorator->decorate($phpDocNode, $node);
}

return $phpDocNode;
}

public function parseTag(TokenIterator $tokenIterator): PhpDocTagNode
{
// replace generic nodes with DoctrineAnnotations
if (! $tokenIterator instanceof BetterTokenIterator) {
throw new ShouldNotHappenException();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?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\Contract\PhpDocParser\PhpDocNodeDecoratorInterface;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
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 implements PhpDocNodeDecoratorInterface
{
public function __construct(
private readonly NameScopeFactory $nameScopeFactory,
private readonly PhpDocNodeTraverser $phpDocNodeTraverser
) {
}

public function decorate(PhpDocNode $phpDocNode, PhpNode $phpNode): void
{
$this->phpDocNodeTraverser->traverseWithCallable($phpDocNode, '', function (Node $node) use (
$phpNode
): 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 $phpNode): ?string
{
if (! $constExprNode instanceof ConstFetchNode) {
return null;
}

$nameScope = $this->nameScopeFactory->createNameScopeFromNodeWithoutTemplateTypes($phpNode);
return $nameScope->resolveStringName($constExprNode->className);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use Rector\BetterPhpDocParser\Attributes\AttributeMirrorer;
use Rector\BetterPhpDocParser\Contract\PhpDocParser\PhpDocNodeDecoratorInterface;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\PhpDoc\SpacelessPhpDocTagNode;
use Rector\BetterPhpDocParser\PhpDocInfo\TokenIteratorFactory;
use Rector\BetterPhpDocParser\ValueObject\DoctrineAnnotation\SilentKeyMap;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\BetterPhpDocParser\ValueObject\StartAndEnd;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Util\StringUtils;

final class DoctrineAnnotationDecorator
final class DoctrineAnnotationDecorator implements PhpDocNodeDecoratorInterface
{
/**
* Special short annotations, that are resolved as FQN by Doctrine annotation parser
Expand All @@ -45,24 +44,18 @@ final class DoctrineAnnotationDecorator
private const NESTED_ANNOTATION_END_REGEX = '#(\s+)?\}\)(\s+)?#';

public function __construct(
private readonly CurrentNodeProvider $currentNodeProvider,
private readonly ClassAnnotationMatcher $classAnnotationMatcher,
private readonly StaticDoctrineAnnotationParser $staticDoctrineAnnotationParser,
private readonly TokenIteratorFactory $tokenIteratorFactory,
private readonly AttributeMirrorer $attributeMirrorer
) {
}

public function decorate(PhpDocNode $phpDocNode): void
public function decorate(PhpDocNode $phpDocNode, Node $phpNode): void
{
$currentPhpNode = $this->currentNodeProvider->getNode();
if (! $currentPhpNode instanceof Node) {
throw new ShouldNotHappenException();
}

// merge split doctrine nested tags
$this->mergeNestedDoctrineAnnotations($phpDocNode);
$this->transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes($phpDocNode, $currentPhpNode);
$this->transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes($phpDocNode, $phpNode);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?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(\Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear $gear)
{
}
}

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

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

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

final class MultipleParamsChange
{
/**
* @param string $carType
* @param Gear::* $gear
* @param int $speed
*/
public function changeGear($carType, string $gear, $speed)
{
}
}

?>
-----
<?php

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

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

final class MultipleParamsChange
{
/**
* @param string $carType
* @param int $speed
*/
public function changeGear($carType, \Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear $gear, $speed)
{
}
}

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

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

final class SkipAlsoOtherElements
{
public const LEFT = 'left';

public const RIGHT = 'right';

protected $value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

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

final class SkipDifferentType
{
public const LEFT = 'left';

public const RIGHT = 5;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

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

final class SkipNonPublicConst
{
public const LEFT = 'left';

protected const RIGHT = 5;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

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

final class SkipNonScalarTypes
{
public const LEFT = self::class;

public const RIGHT = self::class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

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

final class SkipUnknownClass
{
/**
* @param AnythingNonExisting::* $gear
*/
public function changeGear(string $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';
}
Loading