rector/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php

170 lines
5.7 KiB
PHP
Raw Normal View History

2019-10-13 05:59:52 +00:00
<?php
declare(strict_types=1);
2019-02-28 21:50:53 +00:00
namespace Rector\BetterPhpDocParser\PhpDocParser;
2021-03-21 21:31:18 +00:00
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
2019-02-28 21:50:53 +00:00
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
2019-02-28 21:50:53 +00:00
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use Rector\BetterPhpDocParser\Attributes\Attribute\Attribute;
use Rector\BetterPhpDocParser\PhpDocInfo\TokenIteratorFactory;
use Rector\BetterPhpDocParser\PhpDocNodeMapper;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
use Rector\BetterPhpDocParser\ValueObject\StartAndEnd;
2019-02-28 21:50:53 +00:00
use Symplify\PackageBuilder\Reflection\PrivatesCaller;
2019-09-26 14:26:44 +00:00
/**
* @see \Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\TagValueNodeReprintTest
2019-09-26 14:26:44 +00:00
*/
2019-02-28 21:50:53 +00:00
final class BetterPhpDocParser extends PhpDocParser
{
/**
* @var PrivatesCaller
*/
private $privatesCaller;
/**
* @var PhpDocNodeMapper
2019-02-28 21:50:53 +00:00
*/
private $phpDocNodeMapper;
2019-02-28 21:50:53 +00:00
2019-09-26 14:26:44 +00:00
/**
* @var AnnotationContentResolver
2019-09-26 14:26:44 +00:00
*/
private $annotationContentResolver;
2019-09-26 14:26:44 +00:00
/**
* @var DoctrineAnnotationDecorator
*/
private $doctrineAnnotationDecorator;
2020-05-05 14:37:29 +00:00
/**
* @var TokenIteratorFactory
2020-05-05 14:37:29 +00:00
*/
private $tokenIteratorFactory;
2020-05-05 14:37:29 +00:00
2019-02-28 21:50:53 +00:00
public function __construct(
TypeParser $typeParser,
ConstExprParser $constExprParser,
PhpDocNodeMapper $phpDocNodeMapper,
TokenIteratorFactory $tokenIteratorFactory,
AnnotationContentResolver $annotationContentResolver,
DoctrineAnnotationDecorator $doctrineAnnotationDecorator
2019-02-28 21:50:53 +00:00
) {
parent::__construct($typeParser, $constExprParser);
$this->privatesCaller = new PrivatesCaller();
$this->phpDocNodeMapper = $phpDocNodeMapper;
$this->annotationContentResolver = $annotationContentResolver;
$this->doctrineAnnotationDecorator = $doctrineAnnotationDecorator;
$this->tokenIteratorFactory = $tokenIteratorFactory;
}
2019-02-28 21:50:53 +00:00
public function parse(TokenIterator $tokenIterator): PhpDocNode
{
2020-06-04 22:17:31 +00:00
$tokenIterator->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC);
2019-02-28 21:50:53 +00:00
$tokenIterator->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
$children = [];
if (! $tokenIterator->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
$children[] = $this->parseChildAndStoreItsPositions($tokenIterator);
2020-03-04 22:22:29 +00:00
2019-02-28 21:50:53 +00:00
while ($tokenIterator->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && ! $tokenIterator->isCurrentTokenType(
Lexer::TOKEN_CLOSE_PHPDOC
)) {
2019-02-28 21:50:53 +00:00
$children[] = $this->parseChildAndStoreItsPositions($tokenIterator);
}
}
2020-06-04 22:17:31 +00:00
// might be in the middle of annotations
$tokenIterator->tryConsumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC);
2019-02-28 21:50:53 +00:00
2021-03-21 21:31:18 +00:00
$phpDocNode = new PhpDocNode($children);
// replace generic nodes with DoctrineAnnotations
$this->doctrineAnnotationDecorator->decorate($phpDocNode);
return $phpDocNode;
2019-02-28 21:50:53 +00:00
}
/**
* @param BetterTokenIterator $tokenIterator
*/
public function parseTag(TokenIterator $tokenIterator): PhpDocTagNode
{
2019-10-02 19:18:45 +00:00
$tag = $this->resolveTag($tokenIterator);
$phpDocTagValueNode = $this->parseTagValue($tokenIterator, $tag);
return new PhpDocTagNode($tag, $phpDocTagValueNode);
}
/**
* @param BetterTokenIterator $tokenIterator
*/
2019-02-28 21:50:53 +00:00
public function parseTagValue(TokenIterator $tokenIterator, string $tag): PhpDocTagValueNode
{
$startPosition = $tokenIterator->currentTokenOffset();
$tagValueNode = parent::parseTagValue($tokenIterator, $tag);
$endPosition = $tokenIterator->currentTokenOffset();
2019-09-26 14:26:44 +00:00
$startAndEnd = new StartAndEnd($startPosition, $endPosition);
$tagValueNode->setAttribute(StartAndEnd::class, $startAndEnd);
2019-02-28 21:50:53 +00:00
return $this->phpDocNodeMapper->transform($tagValueNode, $tokenIterator->print());
}
2021-03-21 21:31:18 +00:00
private function parseChildAndStoreItsPositions(TokenIterator $tokenIterator): PhpDocChildNode
2019-02-28 21:50:53 +00:00
{
$originalTokenIterator = clone $tokenIterator;
$docContent = $this->annotationContentResolver->resolveFromTokenIterator($originalTokenIterator);
if (! $tokenIterator instanceof BetterTokenIterator) {
$tokenIterator = $this->tokenIteratorFactory->createFromTokenIterator($tokenIterator);
}
$tokenStart = $tokenIterator->currentPosition();
2021-03-21 21:31:18 +00:00
/** @var PhpDocChildNode $phpDocNode */
2021-01-09 14:51:10 +00:00
$phpDocNode = $this->privatesCaller->callPrivateMethod($this, 'parseChild', [$tokenIterator]);
$tokenEnd = $tokenIterator->currentPosition();
$startAndEnd = new StartAndEnd($tokenStart, $tokenEnd);
2019-02-28 21:50:53 +00:00
$transformedPhpDocNode = $this->phpDocNodeMapper->transform($phpDocNode, $docContent);
$transformedPhpDocNode->setAttribute(Attribute::START_END, $startAndEnd);
2019-02-28 21:50:53 +00:00
return $transformedPhpDocNode;
2019-02-28 21:50:53 +00:00
}
private function resolveTag(BetterTokenIterator $tokenIterator): string
2019-10-02 19:18:45 +00:00
{
$tag = $tokenIterator->currentTokenValue();
$tokenIterator->next();
// there is a space → stop
if ($tokenIterator->isPrecededByHorizontalWhitespace()) {
2019-10-04 12:55:26 +00:00
return $tag;
}
2019-10-02 19:18:45 +00:00
// is not e.g "@var "
// join tags like "@ORM\Column" etc.
if (! $tokenIterator->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
2019-10-02 19:18:45 +00:00
return $tag;
}
// @todo use joinUntil("(")?
2019-10-02 19:18:45 +00:00
$tag .= $tokenIterator->currentTokenValue();
$tokenIterator->next();
return $tag;
}
2019-02-28 21:50:53 +00:00
}