diff --git a/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php b/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php index b89dbb638b82..689b4607ce84 100644 --- a/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php +++ b/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php @@ -29,7 +29,7 @@ public function __construct($value, $key = null) public function __toString() : string { $value = ''; - if ($this->key !== null) { + if ($this->key !== null && !\is_numeric($this->key)) { $value .= $this->key . '='; } if (\is_array($this->value)) { diff --git a/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php b/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php index 63f4e22cb1cd..4044b3135884 100644 --- a/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php +++ b/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php @@ -21,6 +21,7 @@ use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey; use Rector\BetterPhpDocParser\ValueObject\StartAndEnd; use Rector\Core\Util\StringUtils; +use RectorPrefix202311\Webmozart\Assert\Assert; final class DoctrineAnnotationDecorator implements PhpDocNodeDecoratorInterface { /** @@ -175,12 +176,35 @@ private function transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes( if (\strpos($fullyQualifiedAnnotationClass, '\\') === \false && !\in_array($fullyQualifiedAnnotationClass, self::ALLOWED_SHORT_ANNOTATIONS, \true)) { continue; } - $spacelessPhpDocTagNode = $this->createSpacelessPhpDocTagNode($phpDocChildNode->name, $phpDocChildNode->value, $fullyQualifiedAnnotationClass, $currentPhpNode); - $this->attributeMirrorer->mirror($phpDocChildNode, $spacelessPhpDocTagNode); while (isset($phpDocNode->children[$key]) && $phpDocNode->children[$key] !== $phpDocChildNode) { ++$key; } + $phpDocTextNode = new PhpDocTextNode($phpDocChildNode->value->value); + $startAndEnd = $phpDocChildNode->value->getAttribute(PhpDocAttributeKey::START_AND_END); + if (!$startAndEnd instanceof StartAndEnd) { + $spacelessPhpDocTagNode = $this->createSpacelessPhpDocTagNode($phpDocChildNode->name, $phpDocChildNode->value, $fullyQualifiedAnnotationClass, $currentPhpNode); + $this->attributeMirrorer->mirror($phpDocChildNode, $spacelessPhpDocTagNode); + $phpDocNode->children[$key] = $spacelessPhpDocTagNode; + continue; + } + $phpDocTextNode->setAttribute(PhpDocAttributeKey::START_AND_END, $startAndEnd); + $spacelessPhpDocTagNodes = $this->resolveFqnAnnotationSpacelessPhpDocTagNode($phpDocTextNode, $currentPhpNode); + if ($spacelessPhpDocTagNodes === []) { + $spacelessPhpDocTagNode = $this->createSpacelessPhpDocTagNode($phpDocChildNode->name, $phpDocChildNode->value, $fullyQualifiedAnnotationClass, $currentPhpNode); + $this->attributeMirrorer->mirror($phpDocChildNode, $spacelessPhpDocTagNode); + $phpDocNode->children[$key] = $spacelessPhpDocTagNode; + continue; + } + Assert::isAOf($phpDocNode->children[$key], PhpDocTagNode::class); + $texts = \explode("\n@\\", $phpDocChildNode->value->value); + $phpDocNode->children[$key]->value = new GenericTagValueNode($texts[0]); + $phpDocNode->children[$key]->value->setAttribute(PhpDocAttributeKey::START_AND_END, $startAndEnd); + $spacelessPhpDocTagNode = $this->createSpacelessPhpDocTagNode($phpDocNode->children[$key]->name, $phpDocNode->children[$key]->value, $fullyQualifiedAnnotationClass, $currentPhpNode); + $this->attributeMirrorer->mirror($phpDocNode->children[$key], $spacelessPhpDocTagNode); $phpDocNode->children[$key] = $spacelessPhpDocTagNode; + // require to reprint the generic + $phpDocNode->children[$key]->setAttribute(PhpDocAttributeKey::IS_AFTER_GENERIC, \true); + \array_splice($phpDocNode->children, $key + 1, 0, $spacelessPhpDocTagNodes); } } private function processDescriptionAsSpacelessPhpDoctagNode(PhpDocNode $phpDocNode, PhpDocTagNode $phpDocTagNode, Node $currentPhpNode, int $key) : void diff --git a/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php b/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php index facb2a27f3d3..83b6f683a77c 100644 --- a/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php +++ b/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php @@ -15,6 +15,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\PhpDocParser\Lexer\Lexer; +use Rector\BetterPhpDocParser\PhpDoc\SpacelessPhpDocTagNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\BetterPhpDocParser\PhpDocNodeVisitor\ChangedPhpDocNodeVisitor; use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey; @@ -278,7 +279,10 @@ private function correctPreviouslyReprintedFirstNode(int $key, StartAndEnd $star private function shouldReprint(PhpDocChildNode $phpDocChildNode) : bool { $this->changedPhpDocNodeTraverser->traverse($phpDocChildNode); - return $this->changedPhpDocNodeVisitor->hasChanged(); + if ($this->changedPhpDocNodeVisitor->hasChanged()) { + return \true; + } + return $phpDocChildNode instanceof SpacelessPhpDocTagNode && $phpDocChildNode->getAttribute(PhpDocAttributeKey::IS_AFTER_GENERIC) === \true; } private function standardPrintPhpDocChildNode(PhpDocChildNode $phpDocChildNode) : string { diff --git a/packages/BetterPhpDocParser/ValueObject/PhpDocAttributeKey.php b/packages/BetterPhpDocParser/ValueObject/PhpDocAttributeKey.php index 85a046fbbdff..f4442390c941 100644 --- a/packages/BetterPhpDocParser/ValueObject/PhpDocAttributeKey.php +++ b/packages/BetterPhpDocParser/ValueObject/PhpDocAttributeKey.php @@ -27,4 +27,8 @@ final class PhpDocAttributeKey * @var string */ public const ORIG_NODE = NativePhpDocAttributeKey::ORIG_NODE; + /** + * @var string + */ + public const IS_AFTER_GENERIC = 'is_after_generic'; } diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 6f735e1f3851..a67ae037e0aa 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -19,12 +19,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = 'd864d7b856e7bb8b7e98db96793ceb1036c1bf7b'; + public const PACKAGE_VERSION = '19b42014a5d00de5181bc2463d4c368c5cf194d7'; /** * @api * @var string */ - public const RELEASE_DATE = '2023-11-23 16:49:59'; + public const RELEASE_DATE = '2023-11-25 08:28:40'; /** * @var int */