2019-10-13 05:59:52 +00:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2022-06-06 17:12:56 +00:00
|
|
|
namespace Rector\BetterPhpDocParser\PhpDocInfo;
|
2019-02-28 21:50:53 +00:00
|
|
|
|
2023-04-04 00:56:57 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\Node;
|
2023-04-05 00:15:15 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
|
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
2023-04-04 00:56:57 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
|
2023-02-08 15:30:12 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PHPStan\PhpDocParser\Lexer\Lexer;
|
|
|
|
use PHPStan\Type\MixedType;
|
|
|
|
use PHPStan\Type\Type;
|
|
|
|
use Rector\BetterPhpDocParser\Annotation\AnnotationNaming;
|
2024-02-22 12:50:50 +00:00
|
|
|
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
|
2022-06-06 17:12:56 +00:00
|
|
|
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
|
|
|
|
use Rector\BetterPhpDocParser\PhpDoc\SpacelessPhpDocTagNode;
|
|
|
|
use Rector\BetterPhpDocParser\PhpDocNodeFinder\PhpDocNodeByTypeFinder;
|
|
|
|
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
|
2023-04-04 00:56:57 +00:00
|
|
|
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
|
2022-06-06 17:12:56 +00:00
|
|
|
use Rector\BetterPhpDocParser\ValueObject\Type\ShortenedIdentifierTypeNode;
|
2022-08-29 20:49:28 +00:00
|
|
|
use Rector\PhpDocParser\PhpDocParser\PhpDocNodeTraverser;
|
2022-06-06 17:12:56 +00:00
|
|
|
use Rector\StaticTypeMapper\StaticTypeMapper;
|
2019-09-03 09:11:45 +00:00
|
|
|
/**
|
2021-03-12 19:13:27 +00:00
|
|
|
* @see \Rector\Tests\BetterPhpDocParser\PhpDocInfo\PhpDocInfo\PhpDocInfoTest
|
2019-09-03 09:11:45 +00:00
|
|
|
*/
|
2019-02-28 21:50:53 +00:00
|
|
|
final class PhpDocInfo
|
|
|
|
{
|
2021-05-10 23:39:21 +00:00
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-08-23 00:20:32 +00:00
|
|
|
* @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode
|
2021-05-10 23:39:21 +00:00
|
|
|
*/
|
2019-02-28 21:50:53 +00:00
|
|
|
private $phpDocNode;
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator
|
2019-02-28 21:50:53 +00:00
|
|
|
*/
|
2021-05-10 23:39:21 +00:00
|
|
|
private $betterTokenIterator;
|
2019-09-06 10:30:58 +00:00
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\StaticTypeMapper\StaticTypeMapper
|
2019-09-06 10:30:58 +00:00
|
|
|
*/
|
|
|
|
private $staticTypeMapper;
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-08-23 00:20:32 +00:00
|
|
|
* @var \PhpParser\Node
|
2019-09-06 10:30:58 +00:00
|
|
|
*/
|
|
|
|
private $node;
|
2020-07-28 23:41:20 +00:00
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\BetterPhpDocParser\Annotation\AnnotationNaming
|
2020-10-11 14:17:43 +00:00
|
|
|
*/
|
2021-01-19 19:45:30 +00:00
|
|
|
private $annotationNaming;
|
2021-07-01 14:10:40 +00:00
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-07-01 14:10:40 +00:00
|
|
|
* @var \Rector\BetterPhpDocParser\PhpDocNodeFinder\PhpDocNodeByTypeFinder
|
|
|
|
*/
|
|
|
|
private $phpDocNodeByTypeFinder;
|
2023-06-08 22:00:17 +00:00
|
|
|
/**
|
|
|
|
* @var array<class-string<PhpDocTagValueNode>, string>
|
|
|
|
*/
|
|
|
|
private const TAGS_TYPES_TO_NAMES = [ReturnTagValueNode::class => '@return', ParamTagValueNode::class => '@param', VarTagValueNode::class => '@var', MethodTagValueNode::class => '@method', PropertyTagValueNode::class => '@property'];
|
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
private $isSingleLine = \false;
|
|
|
|
/**
|
|
|
|
* @readonly
|
|
|
|
* @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode
|
|
|
|
*/
|
|
|
|
private $originalPhpDocNode;
|
2023-09-11 07:55:34 +00:00
|
|
|
public function __construct(PhpDocNode $phpDocNode, BetterTokenIterator $betterTokenIterator, StaticTypeMapper $staticTypeMapper, \PhpParser\Node $node, AnnotationNaming $annotationNaming, PhpDocNodeByTypeFinder $phpDocNodeByTypeFinder)
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2021-03-20 15:27:18 +00:00
|
|
|
$this->phpDocNode = $phpDocNode;
|
2021-04-06 18:36:50 +00:00
|
|
|
$this->betterTokenIterator = $betterTokenIterator;
|
2019-09-06 10:30:58 +00:00
|
|
|
$this->staticTypeMapper = $staticTypeMapper;
|
|
|
|
$this->node = $node;
|
2021-01-19 15:03:26 +00:00
|
|
|
$this->annotationNaming = $annotationNaming;
|
2021-07-01 14:10:40 +00:00
|
|
|
$this->phpDocNodeByTypeFinder = $phpDocNodeByTypeFinder;
|
2021-05-10 23:39:21 +00:00
|
|
|
$this->originalPhpDocNode = clone $phpDocNode;
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$betterTokenIterator->containsTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
|
2021-05-10 23:39:21 +00:00
|
|
|
$this->isSingleLine = \true;
|
|
|
|
}
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
2022-07-17 12:27:00 +00:00
|
|
|
/**
|
|
|
|
* @api
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
public function addPhpDocTagNode(PhpDocChildNode $phpDocChildNode) : void
|
2020-01-29 13:36:09 +00:00
|
|
|
{
|
|
|
|
$this->phpDocNode->children[] = $phpDocChildNode;
|
2021-04-04 15:37:02 +00:00
|
|
|
// to give node more space
|
|
|
|
$this->makeMultiLined();
|
2020-01-29 13:36:09 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getPhpDocNode() : PhpDocNode
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
|
|
|
return $this->phpDocNode;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getOriginalPhpDocNode() : PhpDocNode
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
|
|
|
return $this->originalPhpDocNode;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @return mixed[]
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function getTokens() : array
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2021-04-06 18:36:50 +00:00
|
|
|
return $this->betterTokenIterator->getTokens();
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function getTokenCount() : int
|
2020-03-29 11:08:25 +00:00
|
|
|
{
|
2021-04-06 18:36:50 +00:00
|
|
|
return $this->betterTokenIterator->count();
|
2020-03-29 11:08:25 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getVarTagValueNode(string $tagName = '@var') : ?VarTagValueNode
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2021-06-25 15:32:16 +00:00
|
|
|
return $this->phpDocNode->getVarTagValues($tagName)[0] ?? null;
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
|
|
|
/**
|
2021-03-19 14:33:58 +00:00
|
|
|
* @return array<PhpDocTagNode>
|
2019-02-28 21:50:53 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function getTagsByName(string $name) : array
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2021-06-30 21:52:31 +00:00
|
|
|
// for simple tag names only
|
|
|
|
if (\strpos($name, '\\') !== \false) {
|
|
|
|
return [];
|
|
|
|
}
|
2019-02-28 21:50:53 +00:00
|
|
|
$tags = $this->phpDocNode->getTags();
|
2021-06-30 21:52:31 +00:00
|
|
|
$name = $this->annotationNaming->normalizeName($name);
|
2022-08-23 16:16:02 +00:00
|
|
|
$tags = \array_filter($tags, static function (PhpDocTagNode $phpDocTagNode) use($name) : bool {
|
|
|
|
return $phpDocTagNode->name === $name;
|
2019-02-28 21:50:53 +00:00
|
|
|
});
|
2021-05-09 20:15:43 +00:00
|
|
|
return \array_values($tags);
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getParamType(string $name) : Type
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2021-03-20 15:27:18 +00:00
|
|
|
$paramTagValueNodes = $this->getParamTagValueByName($name);
|
|
|
|
return $this->getTypeOrMixed($paramTagValueNodes);
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
2019-10-19 12:17:15 +00:00
|
|
|
/**
|
2020-12-04 23:22:12 +00:00
|
|
|
* @return ParamTagValueNode[]
|
2019-10-19 12:17:15 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function getParamTagValueNodes() : array
|
2019-10-19 12:17:15 +00:00
|
|
|
{
|
2020-12-04 23:22:12 +00:00
|
|
|
return $this->phpDocNode->getParamTagValues();
|
2019-10-19 12:17:15 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getVarType(string $tagName = '@var') : Type
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2021-06-25 15:32:16 +00:00
|
|
|
return $this->getTypeOrMixed($this->getVarTagValueNode($tagName));
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getReturnType() : Type
|
2019-02-28 21:50:53 +00:00
|
|
|
{
|
2020-04-08 11:48:33 +00:00
|
|
|
return $this->getTypeOrMixed($this->getReturnTagValue());
|
2019-08-26 22:15:56 +00:00
|
|
|
}
|
2021-07-02 20:55:14 +00:00
|
|
|
/**
|
2022-08-09 19:37:14 +00:00
|
|
|
* @param class-string<Node> $type
|
2021-01-19 01:15:32 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasByType(string $type) : bool
|
2019-12-27 12:44:45 +00:00
|
|
|
{
|
2021-07-01 14:46:27 +00:00
|
|
|
return $this->phpDocNodeByTypeFinder->findByType($this->phpDocNode, $type) !== [];
|
2019-12-27 12:44:45 +00:00
|
|
|
}
|
2021-01-19 21:32:28 +00:00
|
|
|
/**
|
2022-08-09 19:37:14 +00:00
|
|
|
* @param array<class-string<Node>> $types
|
2021-01-19 21:32:28 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasByTypes(array $types) : bool
|
2021-01-19 21:32:28 +00:00
|
|
|
{
|
|
|
|
foreach ($types as $type) {
|
2021-02-07 21:22:03 +00:00
|
|
|
if ($this->hasByType($type)) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2021-01-19 21:32:28 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2021-01-19 21:32:28 +00:00
|
|
|
}
|
2020-10-11 14:17:43 +00:00
|
|
|
/**
|
|
|
|
* @param string[] $names
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasByNames(array $names) : bool
|
2020-04-08 11:48:33 +00:00
|
|
|
{
|
|
|
|
foreach ($names as $name) {
|
|
|
|
if ($this->hasByName($name)) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2020-04-08 11:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2020-04-08 11:48:33 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasByName(string $name) : bool
|
2020-01-31 08:01:07 +00:00
|
|
|
{
|
|
|
|
return (bool) $this->getTagsByName($name);
|
|
|
|
}
|
2023-09-29 07:28:16 +00:00
|
|
|
/**
|
|
|
|
* @api
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getByName(string $name) : ?Node
|
2021-04-04 09:01:11 +00:00
|
|
|
{
|
|
|
|
return $this->getTagsByName($name)[0] ?? null;
|
|
|
|
}
|
2021-01-19 01:15:32 +00:00
|
|
|
/**
|
2022-08-09 13:39:17 +00:00
|
|
|
* @param string[] $classes
|
2021-01-19 01:15:32 +00:00
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getByAnnotationClasses(array $classes) : ?DoctrineAnnotationTagValueNode
|
2019-08-30 06:27:03 +00:00
|
|
|
{
|
2021-07-01 14:46:27 +00:00
|
|
|
$doctrineAnnotationTagValueNodes = $this->phpDocNodeByTypeFinder->findDoctrineAnnotationsByClasses($this->phpDocNode, $classes);
|
|
|
|
return $doctrineAnnotationTagValueNodes[0] ?? null;
|
2021-04-04 09:01:11 +00:00
|
|
|
}
|
2022-12-23 17:10:25 +00:00
|
|
|
/**
|
|
|
|
* @api doctrine/symfony
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getByAnnotationClass(string $class) : ?DoctrineAnnotationTagValueNode
|
2021-06-30 21:52:31 +00:00
|
|
|
{
|
2021-07-01 14:46:27 +00:00
|
|
|
$doctrineAnnotationTagValueNodes = $this->phpDocNodeByTypeFinder->findDoctrineAnnotationsByClass($this->phpDocNode, $class);
|
|
|
|
return $doctrineAnnotationTagValueNodes[0] ?? null;
|
2021-06-30 21:52:31 +00:00
|
|
|
}
|
2023-06-04 17:52:08 +00:00
|
|
|
/**
|
2023-10-01 11:38:36 +00:00
|
|
|
* @api used in tests, doctrine
|
2023-06-04 17:52:08 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasByAnnotationClass(string $class) : bool
|
2021-04-04 09:01:11 +00:00
|
|
|
{
|
2021-06-30 21:52:31 +00:00
|
|
|
return $this->findByAnnotationClass($class) !== [];
|
2021-04-04 09:01:11 +00:00
|
|
|
}
|
|
|
|
/**
|
2021-04-05 09:53:03 +00:00
|
|
|
* @param string[] $annotationsClasses
|
2021-04-04 09:01:11 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasByAnnotationClasses(array $annotationsClasses) : bool
|
2021-04-04 09:01:11 +00:00
|
|
|
{
|
2023-03-23 23:21:34 +00:00
|
|
|
return $this->getByAnnotationClasses($annotationsClasses) instanceof DoctrineAnnotationTagValueNode;
|
2021-04-04 09:01:11 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function findOneByAnnotationClass(string $desiredClass) : ?DoctrineAnnotationTagValueNode
|
2021-04-04 09:01:11 +00:00
|
|
|
{
|
2021-06-30 21:52:31 +00:00
|
|
|
$foundTagValueNodes = $this->findByAnnotationClass($desiredClass);
|
|
|
|
return $foundTagValueNodes[0] ?? null;
|
|
|
|
}
|
2021-03-19 14:33:58 +00:00
|
|
|
/**
|
|
|
|
* @template T of \PHPStan\PhpDocParser\Ast\Node
|
2021-07-01 23:23:13 +00:00
|
|
|
* @param class-string<T> $typeToRemove
|
2021-03-19 14:33:58 +00:00
|
|
|
*/
|
2023-09-11 07:37:02 +00:00
|
|
|
public function removeByType(string $typeToRemove) : bool
|
2019-12-27 00:56:35 +00:00
|
|
|
{
|
2023-09-11 07:37:02 +00:00
|
|
|
$hasChanged = \false;
|
2022-06-07 08:22:29 +00:00
|
|
|
$phpDocNodeTraverser = new PhpDocNodeTraverser();
|
2023-09-11 13:16:45 +00:00
|
|
|
$phpDocNodeTraverser->traverseWithCallable($this->phpDocNode, '', static function (Node $node) use($typeToRemove, &$hasChanged) : ?int {
|
2023-01-02 11:58:30 +00:00
|
|
|
if ($node instanceof PhpDocTagNode && $node->value instanceof $typeToRemove) {
|
2022-05-12 09:11:03 +00:00
|
|
|
// keep special annotation for tools
|
2022-02-18 09:30:35 +00:00
|
|
|
if (\strncmp($node->name, '@psalm-', \strlen('@psalm-')) === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (\strncmp($node->name, '@phpstan-', \strlen('@phpstan-')) === 0) {
|
2021-10-22 13:24:11 +00:00
|
|
|
return null;
|
|
|
|
}
|
2023-09-11 07:37:02 +00:00
|
|
|
$hasChanged = \true;
|
2022-06-07 08:22:29 +00:00
|
|
|
return PhpDocNodeTraverser::NODE_REMOVE;
|
2021-07-08 15:36:45 +00:00
|
|
|
}
|
2023-01-02 11:58:30 +00:00
|
|
|
if (!$node instanceof $typeToRemove) {
|
2021-07-01 23:23:13 +00:00
|
|
|
return null;
|
2019-12-27 00:56:35 +00:00
|
|
|
}
|
2023-09-11 07:37:02 +00:00
|
|
|
$hasChanged = \true;
|
2022-06-07 08:22:29 +00:00
|
|
|
return PhpDocNodeTraverser::NODE_REMOVE;
|
2021-07-01 23:23:13 +00:00
|
|
|
});
|
2023-09-11 07:37:02 +00:00
|
|
|
return $hasChanged;
|
2019-12-27 00:56:35 +00:00
|
|
|
}
|
2024-04-03 05:38:25 +00:00
|
|
|
public function removeByName(string $tagName) : bool
|
|
|
|
{
|
|
|
|
$tagName = '@' . \ltrim($tagName, '@');
|
|
|
|
$hasChanged = \false;
|
|
|
|
$phpDocNodeTraverser = new PhpDocNodeTraverser();
|
|
|
|
$phpDocNodeTraverser->traverseWithCallable($this->phpDocNode, '', static function (Node $node) use($tagName, &$hasChanged) : ?int {
|
|
|
|
if ($node instanceof PhpDocTagNode && $node->name === $tagName) {
|
|
|
|
$hasChanged = \true;
|
|
|
|
return PhpDocNodeTraverser::NODE_REMOVE;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
});
|
|
|
|
return $hasChanged;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function addTagValueNode(PhpDocTagValueNode $phpDocTagValueNode) : void
|
2020-02-04 08:39:57 +00:00
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($phpDocTagValueNode instanceof DoctrineAnnotationTagValueNode) {
|
|
|
|
if ($phpDocTagValueNode->identifierTypeNode instanceof ShortenedIdentifierTypeNode) {
|
2022-04-09 08:05:52 +00:00
|
|
|
$name = '@' . $phpDocTagValueNode->identifierTypeNode;
|
|
|
|
} else {
|
|
|
|
$name = '@\\' . $phpDocTagValueNode->identifierTypeNode;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
$spacelessPhpDocTagNode = new SpacelessPhpDocTagNode($name, $phpDocTagValueNode);
|
2021-02-08 23:42:47 +00:00
|
|
|
$this->addPhpDocTagNode($spacelessPhpDocTagNode);
|
|
|
|
return;
|
2021-01-30 15:06:43 +00:00
|
|
|
}
|
2020-03-02 21:16:08 +00:00
|
|
|
$name = $this->resolveNameForPhpDocTagValueNode($phpDocTagValueNode);
|
2021-11-15 13:56:07 +00:00
|
|
|
if (!\is_string($name)) {
|
|
|
|
return;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
$phpDocTagNode = new PhpDocTagNode($name, $phpDocTagValueNode);
|
2021-03-19 14:33:58 +00:00
|
|
|
$this->addPhpDocTagNode($phpDocTagNode);
|
2020-02-04 08:39:57 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function isNewNode() : bool
|
2020-02-16 21:29:32 +00:00
|
|
|
{
|
|
|
|
if ($this->phpDocNode->children === []) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2020-02-16 21:29:32 +00:00
|
|
|
}
|
2021-04-06 18:36:50 +00:00
|
|
|
return $this->betterTokenIterator->count() === 0;
|
2020-02-16 21:29:32 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function isSingleLine() : bool
|
2020-07-22 13:08:40 +00:00
|
|
|
{
|
|
|
|
return $this->isSingleLine;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function hasInvalidTag(string $name) : bool
|
2021-04-09 17:36:06 +00:00
|
|
|
{
|
|
|
|
// fallback for invalid tag value node
|
|
|
|
foreach ($this->phpDocNode->children as $phpDocChildNode) {
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$phpDocChildNode instanceof PhpDocTagNode) {
|
2021-04-09 17:36:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($phpDocChildNode->name !== $name) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$phpDocChildNode->value instanceof InvalidTagValueNode) {
|
2021-04-09 17:36:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2021-04-09 17:36:06 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2021-04-09 17:36:06 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getReturnTagValue() : ?ReturnTagValueNode
|
2020-07-27 09:26:41 +00:00
|
|
|
{
|
|
|
|
$returnTagValueNodes = $this->phpDocNode->getReturnTagValues();
|
|
|
|
return $returnTagValueNodes[0] ?? null;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function getParamTagValueByName(string $name) : ?ParamTagValueNode
|
2020-04-23 23:21:05 +00:00
|
|
|
{
|
2021-05-09 20:15:43 +00:00
|
|
|
$desiredParamNameWithDollar = '$' . \ltrim($name, '$');
|
2021-03-20 15:27:18 +00:00
|
|
|
foreach ($this->getParamTagValueNodes() as $paramTagValueNode) {
|
|
|
|
if ($paramTagValueNode->parameterName !== $desiredParamNameWithDollar) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return $paramTagValueNode;
|
|
|
|
}
|
|
|
|
return null;
|
2020-04-23 23:21:05 +00:00
|
|
|
}
|
2024-03-21 09:55:11 +00:00
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getTemplateNames() : array
|
|
|
|
{
|
|
|
|
$templateNames = [];
|
|
|
|
foreach ($this->phpDocNode->getTemplateTagValues() as $templateTagValueNode) {
|
|
|
|
$templateNames[] = $templateTagValueNode->name;
|
|
|
|
}
|
|
|
|
return $templateNames;
|
|
|
|
}
|
2020-12-28 13:01:27 +00:00
|
|
|
/**
|
|
|
|
* @return TemplateTagValueNode[]
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function getTemplateTagValueNodes() : array
|
2020-12-28 13:01:27 +00:00
|
|
|
{
|
|
|
|
return $this->phpDocNode->getTemplateTagValues();
|
|
|
|
}
|
2021-04-06 17:33:09 +00:00
|
|
|
/**
|
2023-09-11 14:54:44 +00:00
|
|
|
* @deprecated Change doc block and print directly in the node instead
|
2021-04-06 17:33:09 +00:00
|
|
|
* Should be handled by attributes of phpdoc node - if stard_and_end is missing in one of nodes, it has been changed
|
2023-09-11 21:30:42 +00:00
|
|
|
*
|
|
|
|
* @api
|
2021-04-06 17:33:09 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function markAsChanged() : void
|
2021-01-19 15:03:26 +00:00
|
|
|
{
|
2020-12-28 16:57:21 +00:00
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function makeMultiLined() : void
|
2021-04-04 09:01:11 +00:00
|
|
|
{
|
2021-05-09 20:15:43 +00:00
|
|
|
$this->isSingleLine = \false;
|
2021-03-30 14:24:16 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
public function getNode() : \PhpParser\Node
|
2021-05-25 16:37:18 +00:00
|
|
|
{
|
|
|
|
return $this->node;
|
|
|
|
}
|
2023-02-08 15:30:12 +00:00
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getAnnotationClassNames() : array
|
|
|
|
{
|
|
|
|
/** @var IdentifierTypeNode[] $identifierTypeNodes */
|
|
|
|
$identifierTypeNodes = $this->phpDocNodeByTypeFinder->findByType($this->phpDocNode, IdentifierTypeNode::class);
|
|
|
|
$resolvedClasses = [];
|
|
|
|
foreach ($identifierTypeNodes as $identifierTypeNode) {
|
|
|
|
$resolvedClasses[] = \ltrim($identifierTypeNode->name, '@');
|
|
|
|
}
|
|
|
|
return $resolvedClasses;
|
|
|
|
}
|
2023-04-05 00:15:15 +00:00
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getGenericTagClassNames() : array
|
|
|
|
{
|
|
|
|
/** @var GenericTagValueNode[] $genericTagValueNodes */
|
|
|
|
$genericTagValueNodes = $this->phpDocNodeByTypeFinder->findByType($this->phpDocNode, GenericTagValueNode::class);
|
|
|
|
$resolvedClasses = [];
|
|
|
|
foreach ($genericTagValueNodes as $genericTagValueNode) {
|
2023-09-13 12:31:43 +00:00
|
|
|
if ($genericTagValueNode->value !== '') {
|
|
|
|
$resolvedClasses[] = $genericTagValueNode->value;
|
|
|
|
}
|
2023-04-05 00:15:15 +00:00
|
|
|
}
|
|
|
|
return $resolvedClasses;
|
|
|
|
}
|
2023-04-04 00:56:57 +00:00
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getConstFetchNodeClassNames() : array
|
|
|
|
{
|
|
|
|
$phpDocNodeTraverser = new PhpDocNodeTraverser();
|
|
|
|
$classNames = [];
|
|
|
|
$phpDocNodeTraverser->traverseWithCallable($this->phpDocNode, '', static function (Node $node) use(&$classNames) : ?ConstTypeNode {
|
|
|
|
if (!$node instanceof ConstTypeNode) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (!$node->constExpr instanceof ConstFetchNode) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
$classNames[] = $node->constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
|
|
|
|
return $node;
|
|
|
|
});
|
|
|
|
return $classNames;
|
|
|
|
}
|
2024-02-22 12:50:50 +00:00
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getArrayItemNodeClassNames() : array
|
|
|
|
{
|
|
|
|
$phpDocNodeTraverser = new PhpDocNodeTraverser();
|
|
|
|
$classNames = [];
|
|
|
|
$phpDocNodeTraverser->traverseWithCallable($this->phpDocNode, '', static function (Node $node) use(&$classNames) : ?ArrayItemNode {
|
|
|
|
if (!$node instanceof ArrayItemNode) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
$resolvedClass = $node->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
|
|
|
|
if ($resolvedClass === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
$classNames[] = $resolvedClass;
|
|
|
|
return $node;
|
|
|
|
});
|
|
|
|
return $classNames;
|
|
|
|
}
|
2023-10-01 11:38:36 +00:00
|
|
|
/**
|
|
|
|
* @param class-string $desiredClass
|
|
|
|
* @return DoctrineAnnotationTagValueNode[]
|
|
|
|
*/
|
|
|
|
public function findByAnnotationClass(string $desiredClass) : array
|
|
|
|
{
|
|
|
|
return $this->phpDocNodeByTypeFinder->findDoctrineAnnotationsByClass($this->phpDocNode, $desiredClass);
|
|
|
|
}
|
2022-12-23 17:10:25 +00:00
|
|
|
private function resolveNameForPhpDocTagValueNode(PhpDocTagValueNode $phpDocTagValueNode) : ?string
|
2021-11-15 13:56:07 +00:00
|
|
|
{
|
|
|
|
foreach (self::TAGS_TYPES_TO_NAMES as $tagValueNodeType => $name) {
|
|
|
|
/** @var class-string<PhpDocTagNode> $tagValueNodeType */
|
2023-01-02 11:58:30 +00:00
|
|
|
if ($phpDocTagValueNode instanceof $tagValueNodeType) {
|
2021-11-15 13:56:07 +00:00
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2021-07-31 11:40:13 +00:00
|
|
|
/**
|
|
|
|
* @return \PHPStan\Type\MixedType|\PHPStan\Type\Type
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
private function getTypeOrMixed(?PhpDocTagValueNode $phpDocTagValueNode)
|
2020-04-08 11:48:33 +00:00
|
|
|
{
|
2023-03-23 23:21:34 +00:00
|
|
|
if (!$phpDocTagValueNode instanceof PhpDocTagValueNode) {
|
2022-06-07 08:22:29 +00:00
|
|
|
return new MixedType();
|
2020-04-08 11:48:33 +00:00
|
|
|
}
|
|
|
|
return $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($phpDocTagValueNode, $this->node);
|
|
|
|
}
|
2019-02-28 21:50:53 +00:00
|
|
|
}
|