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;
|
2019-08-26 09:37:02 +00:00
|
|
|
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;
|
2021-04-04 09:01:11 +00:00
|
|
|
use Rector\BetterPhpDocParser\PhpDocInfo\TokenIteratorFactory;
|
2021-03-20 15:27:18 +00:00
|
|
|
use Rector\BetterPhpDocParser\PhpDocNodeMapper;
|
2021-04-04 09:01:11 +00:00
|
|
|
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
|
2020-09-01 17:56:30 +00:00
|
|
|
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
|
|
|
/**
|
2021-03-12 19:13:27 +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;
|
|
|
|
|
|
|
|
/**
|
2021-03-20 15:27:18 +00:00
|
|
|
* @var PhpDocNodeMapper
|
2019-02-28 21:50:53 +00:00
|
|
|
*/
|
2021-03-20 15:27:18 +00:00
|
|
|
private $phpDocNodeMapper;
|
2019-02-28 21:50:53 +00:00
|
|
|
|
2019-09-26 14:26:44 +00:00
|
|
|
/**
|
2021-04-04 09:01:11 +00:00
|
|
|
* @var AnnotationContentResolver
|
2019-09-26 14:26:44 +00:00
|
|
|
*/
|
2021-04-04 09:01:11 +00:00
|
|
|
private $annotationContentResolver;
|
2019-09-26 14:26:44 +00:00
|
|
|
|
2020-02-29 18:57:31 +00:00
|
|
|
/**
|
2021-04-04 09:01:11 +00:00
|
|
|
* @var DoctrineAnnotationDecorator
|
2020-02-29 18:57:31 +00:00
|
|
|
*/
|
2021-04-04 09:01:11 +00:00
|
|
|
private $doctrineAnnotationDecorator;
|
2020-02-29 18:57:31 +00:00
|
|
|
|
2020-05-05 14:37:29 +00:00
|
|
|
/**
|
2021-04-04 09:01:11 +00:00
|
|
|
* @var TokenIteratorFactory
|
2020-05-05 14:37:29 +00:00
|
|
|
*/
|
2021-04-04 09:01:11 +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,
|
2021-03-20 15:27:18 +00:00
|
|
|
PhpDocNodeMapper $phpDocNodeMapper,
|
2021-04-04 09:01:11 +00:00
|
|
|
TokenIteratorFactory $tokenIteratorFactory,
|
2020-02-29 18:57:31 +00:00
|
|
|
AnnotationContentResolver $annotationContentResolver,
|
2021-04-05 14:22:24 +00:00
|
|
|
DoctrineAnnotationDecorator $doctrineAnnotationDecorator
|
2019-02-28 21:50:53 +00:00
|
|
|
) {
|
|
|
|
parent::__construct($typeParser, $constExprParser);
|
|
|
|
|
|
|
|
$this->privatesCaller = new PrivatesCaller();
|
2021-03-20 15:27:18 +00:00
|
|
|
$this->phpDocNodeMapper = $phpDocNodeMapper;
|
2020-02-29 18:57:31 +00:00
|
|
|
$this->annotationContentResolver = $annotationContentResolver;
|
2021-04-04 09:01:11 +00:00
|
|
|
$this->doctrineAnnotationDecorator = $doctrineAnnotationDecorator;
|
|
|
|
$this->tokenIteratorFactory = $tokenIteratorFactory;
|
2020-01-03 22:44:40 +00:00
|
|
|
}
|
|
|
|
|
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(
|
2020-07-19 19:15:09 +00:00
|
|
|
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);
|
2020-02-29 18:57:31 +00:00
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
// replace generic nodes with DoctrineAnnotations
|
|
|
|
$this->doctrineAnnotationDecorator->decorate($phpDocNode);
|
|
|
|
|
|
|
|
return $phpDocNode;
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
/**
|
|
|
|
* @param BetterTokenIterator $tokenIterator
|
|
|
|
*/
|
2019-08-26 09:37:02 +00:00
|
|
|
public function parseTag(TokenIterator $tokenIterator): PhpDocTagNode
|
|
|
|
{
|
2019-10-02 19:18:45 +00:00
|
|
|
$tag = $this->resolveTag($tokenIterator);
|
2019-08-26 09:37:02 +00:00
|
|
|
|
2021-01-30 15:06:43 +00:00
|
|
|
$phpDocTagValueNode = $this->parseTagValue($tokenIterator, $tag);
|
2019-09-27 14:25:15 +00:00
|
|
|
return new PhpDocTagNode($tag, $phpDocTagValueNode);
|
2019-08-26 09:37:02 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
/**
|
|
|
|
* @param BetterTokenIterator $tokenIterator
|
|
|
|
*/
|
2019-02-28 21:50:53 +00:00
|
|
|
public function parseTagValue(TokenIterator $tokenIterator, string $tag): PhpDocTagValueNode
|
|
|
|
{
|
2021-04-04 09:01:11 +00:00
|
|
|
$startPosition = $tokenIterator->currentTokenOffset();
|
|
|
|
$tagValueNode = parent::parseTagValue($tokenIterator, $tag);
|
|
|
|
$endPosition = $tokenIterator->currentTokenOffset();
|
2019-09-26 14:26:44 +00:00
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
$startAndEnd = new StartAndEnd($startPosition, $endPosition);
|
2020-02-29 18:57:31 +00:00
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
$tagValueNode->setAttribute(StartAndEnd::class, $startAndEnd);
|
2019-02-28 21:50:53 +00:00
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
return $this->phpDocNodeMapper->transform($tagValueNode, $tokenIterator->print());
|
2020-08-05 20:45:36 +00:00
|
|
|
}
|
|
|
|
|
2021-03-21 21:31:18 +00:00
|
|
|
private function parseChildAndStoreItsPositions(TokenIterator $tokenIterator): PhpDocChildNode
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2020-02-29 18:57:31 +00:00
|
|
|
$originalTokenIterator = clone $tokenIterator;
|
|
|
|
$docContent = $this->annotationContentResolver->resolveFromTokenIterator($originalTokenIterator);
|
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
if (! $tokenIterator instanceof BetterTokenIterator) {
|
|
|
|
$tokenIterator = $this->tokenIteratorFactory->createFromTokenIterator($tokenIterator);
|
|
|
|
}
|
|
|
|
|
|
|
|
$tokenStart = $tokenIterator->currentPosition();
|
2021-03-19 14:33:58 +00:00
|
|
|
|
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]);
|
2021-04-04 09:01:11 +00:00
|
|
|
$tokenEnd = $tokenIterator->currentPosition();
|
2020-02-29 19:04:27 +00:00
|
|
|
|
2020-09-01 17:56:30 +00:00
|
|
|
$startAndEnd = new StartAndEnd($tokenStart, $tokenEnd);
|
2019-02-28 21:50:53 +00:00
|
|
|
|
2021-03-20 15:27:18 +00:00
|
|
|
$transformedPhpDocNode = $this->phpDocNodeMapper->transform($phpDocNode, $docContent);
|
|
|
|
$transformedPhpDocNode->setAttribute(Attribute::START_END, $startAndEnd);
|
2019-02-28 21:50:53 +00:00
|
|
|
|
2021-03-20 15:27:18 +00:00
|
|
|
return $transformedPhpDocNode;
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
2019-05-31 08:50:33 +00:00
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
private function resolveTag(BetterTokenIterator $tokenIterator): string
|
2019-10-02 19:18:45 +00:00
|
|
|
{
|
|
|
|
$tag = $tokenIterator->currentTokenValue();
|
|
|
|
$tokenIterator->next();
|
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
// 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.
|
2021-04-04 09:01:11 +00:00
|
|
|
if (! $tokenIterator->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
2019-10-02 19:18:45 +00:00
|
|
|
return $tag;
|
|
|
|
}
|
|
|
|
|
2021-04-04 09:01:11 +00:00
|
|
|
// @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
|
|
|
}
|