Updated Rector to commit e0e88ed2dd5573bde7197d40c770f8b8504646cc

e0e88ed2dd Bump phpdoc-parser 2.0.2 and regenerate preload.php (#6744)
This commit is contained in:
Tomas Votruba 2025-02-19 15:30:21 +00:00
parent 29938fc39c
commit d3d583f3ac
20 changed files with 225 additions and 104 deletions

View File

@ -264,6 +264,7 @@ require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/compatibility_tok
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/Node.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/Comment.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php';

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = 'd4af0ff3eb3ac59534a699a2c3c05e317a10b4d4';
public const PACKAGE_VERSION = 'e0e88ed2dd5573bde7197d40c770f8b8504646cc';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2025-02-19 18:18:05';
public const RELEASE_DATE = '2025-02-19 22:27:43';
/**
* @var int
*/

View File

@ -11,8 +11,6 @@ use PHPStan\Analyser\NodeScopeResolver;
use PHPStan\Analyser\ScopeFactory;
use PHPStan\Parser\Parser;
use PHPStan\PhpDoc\TypeNodeResolver;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPStan\PhpDocParser\ParserConfig;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Application\ChangedNodeScopeRefresher;
@ -267,9 +265,6 @@ final class LazyContainerFactory
$rectorConfig->when(OnlyRuleResolver::class)->needs('$rectors')->giveTagged(RectorInterface::class);
$rectorConfig->singleton(FileProcessor::class);
$rectorConfig->singleton(PostFileProcessor::class);
// phpdoc-parser
$rectorConfig->when(TypeParser::class)->needs('$usedAttributes')->give(['lines' => \true, 'indexes' => \true]);
$rectorConfig->when(ConstExprParser::class)->needs('$usedAttributes')->give(['lines' => \true, 'indexes' => \true]);
$rectorConfig->when(RectorNodeTraverser::class)->needs('$rectors')->giveTagged(RectorInterface::class);
$rectorConfig->when(ConfigInitializer::class)->needs('$rectors')->giveTagged(RectorInterface::class);
$rectorConfig->when(ClassNameImportSkipper::class)->needs('$classNameImportSkipVoters')->giveTagged(ClassNameImportSkipVoterInterface::class);
@ -357,7 +352,8 @@ final class LazyContainerFactory
$this->registerTagged($rectorConfig, self::SCOPE_RESOLVER_NODE_VISITOR_CLASSES, ScopeResolverNodeVisitorInterface::class);
$this->createPHPStanServices($rectorConfig);
$rectorConfig->when(PhpDocNodeMapper::class)->needs('$phpDocNodeVisitors')->giveTagged(BasePhpDocNodeVisitorInterface::class);
$rectorConfig->singleton(ParserConfig::class, static fn(Container $container): ParserConfig => new ParserConfig(['lines' => \true, 'indexes' => \true]));
// phpdoc-parser
$rectorConfig->singleton(ParserConfig::class, static fn(Container $container): ParserConfig => new ParserConfig(['lines' => \true, 'indexes' => \true, 'comments' => \true]));
return $rectorConfig;
}
/**

2
vendor/autoload.php vendored
View File

@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23::getLoader();
return ComposerAutoloaderInit30bd5d3b9b1d532a1d3e11eb20f91e28::getLoader();

View File

@ -9,6 +9,7 @@ return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php',
'PHPStan\\PhpDocParser\\Ast\\Attribute' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Attribute.php',
'PHPStan\\PhpDocParser\\Ast\\Comment' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/Comment.php',
'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayItemNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php',
'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php',
'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23
class ComposerAutoloaderInit30bd5d3b9b1d532a1d3e11eb20f91e28
{
private static $loader;
@ -22,17 +22,17 @@ class ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit30bd5d3b9b1d532a1d3e11eb20f91e28', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit30bd5d3b9b1d532a1d3e11eb20f91e28', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit30bd5d3b9b1d532a1d3e11eb20f91e28::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInit30bd5d3b9b1d532a1d3e11eb20f91e28::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23
class ComposerStaticInit30bd5d3b9b1d532a1d3e11eb20f91e28
{
public static $files = array (
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
@ -228,6 +228,7 @@ class ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php',
'PHPStan\\PhpDocParser\\Ast\\Attribute' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Attribute.php',
'PHPStan\\PhpDocParser\\Ast\\Comment' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/Comment.php',
'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayItemNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php',
'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php',
'PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php',
@ -2864,9 +2865,9 @@ class ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInita9ca9624b9ec3b7183135fb9d7d95d23::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit30bd5d3b9b1d532a1d3e11eb20f91e28::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit30bd5d3b9b1d532a1d3e11eb20f91e28::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit30bd5d3b9b1d532a1d3e11eb20f91e28::$classMap;
}, null, ClassLoader::class);
}

View File

@ -869,17 +869,17 @@
},
{
"name": "phpstan\/phpdoc-parser",
"version": "2.0.2",
"version_normalized": "2.0.2.0",
"version": "2.1.0",
"version_normalized": "2.1.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/phpstan\/phpdoc-parser.git",
"reference": "51087f87dcce2663e1fed4dfd4e56eccd580297e"
"reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/phpstan\/phpdoc-parser\/zipball\/51087f87dcce2663e1fed4dfd4e56eccd580297e",
"reference": "51087f87dcce2663e1fed4dfd4e56eccd580297e",
"url": "https:\/\/api.github.com\/repos\/phpstan\/phpdoc-parser\/zipball\/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
"reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
"shasum": ""
},
"require": {
@ -896,7 +896,7 @@
"phpunit\/phpunit": "^9.6",
"symfony\/process": "^5.2"
},
"time": "2025-02-17T20:25:51+00:00",
"time": "2025-02-19T13:28:12+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -913,7 +913,7 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https:\/\/github.com\/phpstan\/phpdoc-parser\/issues",
"source": "https:\/\/github.com\/phpstan\/phpdoc-parser\/tree\/2.0.2"
"source": "https:\/\/github.com\/phpstan\/phpdoc-parser\/tree\/2.1.0"
},
"install-path": "..\/phpstan\/phpdoc-parser"
},

File diff suppressed because one or more lines are too long

View File

@ -13,9 +13,9 @@ For the complete list of supported PHPDoc features check out PHPStan documentati
* [PHPDoc Basics](https://phpstan.org/writing-php-code/phpdocs-basics) (list of PHPDoc tags)
* [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types) (list of PHPDoc types)
* [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/2.0.x/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc.
* [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/2.1.x/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc.
This parser also supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/2.0.x/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html).
This parser also supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/2.1.x/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html).
## Installation
@ -83,7 +83,7 @@ use PHPStan\PhpDocParser\Printer\Printer;
// basic setup with enabled required lexer attributes
$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true]);
$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true, 'comments' => true]);
$lexer = new Lexer($config);
$constExprParser = new ConstExprParser($config);
$typeParser = new TypeParser($config, $constExprParser);

View File

@ -10,4 +10,5 @@ final class Attribute
public const START_INDEX = 'startIndex';
public const END_INDEX = 'endIndex';
public const ORIGINAL_NODE = 'originalNode';
public const COMMENTS = 'comments';
}

View File

@ -0,0 +1,22 @@
<?php
declare (strict_types=1);
namespace PHPStan\PhpDocParser\Ast;
use function trim;
class Comment
{
public string $text;
public int $startLine;
public int $startIndex;
public function __construct(string $text, int $startLine = -1, int $startIndex = -1)
{
$this->text = $text;
$this->startLine = $startLine;
$this->startIndex = $startIndex;
}
public function getReformattedText() : string
{
return trim($this->text);
}
}

View File

@ -13,6 +13,10 @@ trait NodeAttributes
*/
public function setAttribute(string $key, $value) : void
{
if ($value === null) {
unset($this->attributes[$key]);
return;
}
$this->attributes[$key] = $value;
}
public function hasAttribute(string $key) : bool

View File

@ -49,7 +49,8 @@ class Lexer
public const TOKEN_CLOSE_CURLY_BRACKET = 34;
public const TOKEN_NEGATED = 35;
public const TOKEN_ARROW = 36;
public const TOKEN_LABELS = [self::TOKEN_REFERENCE => '\'&\'', self::TOKEN_UNION => '\'|\'', self::TOKEN_INTERSECTION => '\'&\'', self::TOKEN_NULLABLE => '\'?\'', self::TOKEN_NEGATED => '\'!\'', self::TOKEN_OPEN_PARENTHESES => '\'(\'', self::TOKEN_CLOSE_PARENTHESES => '\')\'', self::TOKEN_OPEN_ANGLE_BRACKET => '\'<\'', self::TOKEN_CLOSE_ANGLE_BRACKET => '\'>\'', self::TOKEN_OPEN_SQUARE_BRACKET => '\'[\'', self::TOKEN_CLOSE_SQUARE_BRACKET => '\']\'', self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'', self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'', self::TOKEN_COMMA => '\',\'', self::TOKEN_COLON => '\':\'', self::TOKEN_VARIADIC => '\'...\'', self::TOKEN_DOUBLE_COLON => '\'::\'', self::TOKEN_DOUBLE_ARROW => '\'=>\'', self::TOKEN_ARROW => '\'->\'', self::TOKEN_EQUAL => '\'=\'', self::TOKEN_OPEN_PHPDOC => '\'/**\'', self::TOKEN_CLOSE_PHPDOC => '\'*/\'', self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG', self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG', self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL', self::TOKEN_FLOAT => 'TOKEN_FLOAT', self::TOKEN_INTEGER => 'TOKEN_INTEGER', self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING', self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING', self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING', self::TOKEN_IDENTIFIER => 'type', self::TOKEN_THIS_VARIABLE => '\'$this\'', self::TOKEN_VARIABLE => 'variable', self::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS', self::TOKEN_OTHER => 'TOKEN_OTHER', self::TOKEN_END => 'TOKEN_END', self::TOKEN_WILDCARD => '*'];
public const TOKEN_COMMENT = 37;
public const TOKEN_LABELS = [self::TOKEN_REFERENCE => '\'&\'', self::TOKEN_UNION => '\'|\'', self::TOKEN_INTERSECTION => '\'&\'', self::TOKEN_NULLABLE => '\'?\'', self::TOKEN_NEGATED => '\'!\'', self::TOKEN_OPEN_PARENTHESES => '\'(\'', self::TOKEN_CLOSE_PARENTHESES => '\')\'', self::TOKEN_OPEN_ANGLE_BRACKET => '\'<\'', self::TOKEN_CLOSE_ANGLE_BRACKET => '\'>\'', self::TOKEN_OPEN_SQUARE_BRACKET => '\'[\'', self::TOKEN_CLOSE_SQUARE_BRACKET => '\']\'', self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'', self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'', self::TOKEN_COMMA => '\',\'', self::TOKEN_COMMENT => '\'//\'', self::TOKEN_COLON => '\':\'', self::TOKEN_VARIADIC => '\'...\'', self::TOKEN_DOUBLE_COLON => '\'::\'', self::TOKEN_DOUBLE_ARROW => '\'=>\'', self::TOKEN_ARROW => '\'->\'', self::TOKEN_EQUAL => '\'=\'', self::TOKEN_OPEN_PHPDOC => '\'/**\'', self::TOKEN_CLOSE_PHPDOC => '\'*/\'', self::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG', self::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG', self::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL', self::TOKEN_FLOAT => 'TOKEN_FLOAT', self::TOKEN_INTEGER => 'TOKEN_INTEGER', self::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING', self::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING', self::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING', self::TOKEN_IDENTIFIER => 'type', self::TOKEN_THIS_VARIABLE => '\'$this\'', self::TOKEN_VARIABLE => 'variable', self::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS', self::TOKEN_OTHER => 'TOKEN_OTHER', self::TOKEN_END => 'TOKEN_END', self::TOKEN_WILDCARD => '*'];
public const VALUE_OFFSET = 0;
public const TYPE_OFFSET = 1;
public const LINE_OFFSET = 2;
@ -104,6 +105,7 @@ class Lexer
self::TOKEN_OPEN_CURLY_BRACKET => '\\{',
self::TOKEN_CLOSE_CURLY_BRACKET => '\\}',
self::TOKEN_COMMA => ',',
self::TOKEN_COMMENT => '\\/\\/[^\\r\\n]*(?=\\n|\\r|\\*/)',
self::TOKEN_VARIADIC => '\\.\\.\\.',
self::TOKEN_DOUBLE_COLON => '::',
self::TOKEN_DOUBLE_ARROW => '=>',

View File

@ -79,8 +79,16 @@ class PhpDocParser
}
$tag = new Ast\PhpDoc\PhpDocTagNode($name, $this->enrichWithAttributes($tokens, new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e), $startLine, $startIndex));
$tokens->forwardToTheEnd();
$comments = $tokens->flushComments();
if ($comments !== []) {
throw new LogicException('Comments should already be flushed');
}
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0);
}
$comments = $tokens->flushComments();
if ($comments !== []) {
throw new LogicException('Comments should already be flushed');
}
return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode($children), 1, 0);
}
/** @phpstan-impure */

View File

@ -4,6 +4,7 @@ declare (strict_types=1);
namespace PHPStan\PhpDocParser\Parser;
use LogicException;
use PHPStan\PhpDocParser\Ast\Comment;
use PHPStan\PhpDocParser\Lexer\Lexer;
use function array_pop;
use function assert;
@ -16,7 +17,9 @@ class TokenIterator
/** @var list<array{string, int, int}> */
private array $tokens;
private int $index;
/** @var int[] */
/** @var list<Comment> */
private array $comments = [];
/** @var list<array{int, list<Comment>}> */
private array $savePoints = [];
/** @var list<int> */
private array $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
@ -113,8 +116,7 @@ class TokenIterator
$this->detectNewline();
}
}
$this->index++;
$this->skipIrrelevantTokens();
$this->next();
}
/**
* @throws ParserException
@ -124,8 +126,7 @@ class TokenIterator
if ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType || $this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
$this->throwError($tokenType, $tokenValue);
}
$this->index++;
$this->skipIrrelevantTokens();
$this->next();
}
/** @phpstan-impure */
public function tryConsumeTokenValue(string $tokenValue) : bool
@ -133,10 +134,18 @@ class TokenIterator
if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {
return \false;
}
$this->index++;
$this->skipIrrelevantTokens();
$this->next();
return \true;
}
/**
* @return list<Comment>
*/
public function flushComments() : array
{
$res = $this->comments;
$this->comments = [];
return $res;
}
/** @phpstan-impure */
public function tryConsumeTokenType(int $tokenType) : bool
{
@ -148,11 +157,12 @@ class TokenIterator
$this->detectNewline();
}
}
$this->index++;
$this->skipIrrelevantTokens();
$this->next();
return \true;
}
/** @phpstan-impure */
/**
* @deprecated Use skipNewLineTokensAndConsumeComments instead (when parsing a type)
*/
public function skipNewLineTokens() : void
{
if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
@ -162,6 +172,24 @@ class TokenIterator
$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
} while ($foundNewLine === \true);
}
public function skipNewLineTokensAndConsumeComments() : void
{
if ($this->currentTokenType() === Lexer::TOKEN_COMMENT) {
$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
$this->next();
}
if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
return;
}
do {
$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
if ($this->currentTokenType() !== Lexer::TOKEN_COMMENT) {
continue;
}
$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
$this->next();
} while ($foundNewLine === \true);
}
private function detectNewline() : void
{
$value = $this->currentTokenValue();
@ -220,7 +248,7 @@ class TokenIterator
}
public function pushSavePoint() : void
{
$this->savePoints[] = $this->index;
$this->savePoints[] = [$this->index, $this->comments];
}
public function dropSavePoint() : void
{
@ -228,9 +256,9 @@ class TokenIterator
}
public function rollback() : void
{
$index = array_pop($this->savePoints);
assert($index !== null);
$this->index = $index;
$savepoint = array_pop($this->savePoints);
assert($savepoint !== null);
[$this->index, $this->comments] = $savepoint;
}
/**
* @throws ParserException

View File

@ -32,7 +32,7 @@ class TypeParser
} else {
$type = $this->parseAtomic($tokens);
$tokens->pushSavePoint();
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
try {
$enrichedType = $this->enrichTypeOnUnionOrIntersection($tokens, $type);
} catch (\PHPStan\PhpDocParser\Parser\ParserException $parserException) {
@ -71,6 +71,10 @@ class TypeParser
$type->setAttribute(Ast\Attribute::START_LINE, $startLine);
$type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
}
$comments = $tokens->flushComments();
if ($this->config->useCommentsAttributes) {
$type->setAttribute(Ast\Attribute::COMMENTS, $comments);
}
if ($this->config->useIndexAttributes) {
$type->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
$type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
@ -91,7 +95,7 @@ class TypeParser
if ($tokens->isCurrentTokenValue('is')) {
$type = $this->parseConditional($tokens, $type);
} else {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
$type = $this->subParseUnion($tokens, $type);
} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
@ -107,9 +111,9 @@ class TypeParser
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$type = $this->subParse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
@ -194,7 +198,7 @@ class TypeParser
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
$types[] = $this->parseAtomic($tokens);
$tokens->pushSavePoint();
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
$tokens->rollback();
break;
@ -208,9 +212,9 @@ class TypeParser
{
$types = [$type];
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$types[] = $this->parseAtomic($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
return new Ast\Type\UnionTypeNode($types);
}
@ -221,7 +225,7 @@ class TypeParser
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
$types[] = $this->parseAtomic($tokens);
$tokens->pushSavePoint();
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
$tokens->rollback();
break;
@ -235,9 +239,9 @@ class TypeParser
{
$types = [$type];
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$types[] = $this->parseAtomic($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
return new Ast\Type\IntersectionTypeNode($types);
}
@ -251,13 +255,13 @@ class TypeParser
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
}
$targetType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$ifType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$elseType = $this->subParse($tokens);
return new Ast\Type\ConditionalTypeNode($subjectType, $targetType, $ifType, $elseType, $negated);
}
@ -272,13 +276,13 @@ class TypeParser
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
}
$targetType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$ifType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_COLON);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$elseType = $this->subParse($tokens);
return new Ast\Type\ConditionalTypeForParameterNode($parameterName, $targetType, $ifType, $elseType, $negated);
}
@ -315,20 +319,21 @@ class TypeParser
public function parseGeneric(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType) : Ast\Type\GenericTypeNode
{
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
$tokens->skipNewLineTokensAndConsumeComments();
$startLine = $baseType->getAttribute(Ast\Attribute::START_LINE);
$startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX);
$genericTypes = [];
$variances = [];
$isFirst = \true;
while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
// trailing comma case
if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
break;
}
$isFirst = \false;
[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
if ($startLine !== null && $startIndex !== null) {
@ -393,18 +398,18 @@ class TypeParser
{
$templates = $hasTemplate ? $this->parseCallableTemplates($tokens) : [];
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$parameters = [];
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
$parameters[] = $this->parseCallableParameter($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
break;
}
$parameters[] = $this->parseCallableParameter($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
}
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
@ -425,14 +430,14 @@ class TypeParser
$templates = [];
$isFirst = \true;
while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
// trailing comma case
if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
break;
}
$isFirst = \false;
$templates[] = $this->parseCallableTemplateArgument($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
return $templates;
@ -587,29 +592,37 @@ class TypeParser
$items = [];
$sealed = \true;
$unsealedType = null;
$done = \false;
do {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
}
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
$sealed = \false;
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
if ($kind === Ast\Type\ArrayShapeNode::KIND_ARRAY) {
$unsealedType = $this->parseArrayShapeUnsealedType($tokens);
} else {
$unsealedType = $this->parseListShapeUnsealedType($tokens);
}
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
break;
}
$items[] = $this->parseArrayShapeItem($tokens);
$tokens->skipNewLineTokens();
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
$done = \true;
}
if ($tokens->currentTokenType() !== Lexer::TOKEN_COMMENT) {
continue;
}
$tokens->next();
} while (!$done);
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
if ($sealed) {
return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
@ -621,6 +634,8 @@ class TypeParser
{
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
// parse any comments above the item
$tokens->skipNewLineTokensAndConsumeComments();
try {
$tokens->pushSavePoint();
$key = $this->parseArrayShapeKey($tokens);
@ -666,15 +681,15 @@ class TypeParser
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$valueType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$keyType = null;
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$keyType = $valueType;
$valueType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
}
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, $keyType), $startLine, $startIndex);
@ -687,9 +702,9 @@ class TypeParser
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$valueType = $this->parse($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
return $this->enrichWithAttributes($tokens, new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, null), $startLine, $startIndex);
}
@ -701,14 +716,14 @@ class TypeParser
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
$items = [];
do {
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
return new Ast\Type\ObjectShapeNode($items);
}
$items[] = $this->parseObjectShapeItem($tokens);
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
$tokens->skipNewLineTokens();
$tokens->skipNewLineTokensAndConsumeComments();
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
return new Ast\Type\ObjectShapeNode($items);
}
@ -717,6 +732,7 @@ class TypeParser
{
$startLine = $tokens->currentTokenLine();
$startIndex = $tokens->currentTokenIndex();
$tokens->skipNewLineTokensAndConsumeComments();
$key = $this->parseObjectShapeKey($tokens);
$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
$tokens->consumeTokenType(Lexer::TOKEN_COLON);

View File

@ -7,12 +7,14 @@ class ParserConfig
{
public bool $useLinesAttributes;
public bool $useIndexAttributes;
public bool $useCommentsAttributes;
/**
* @param array{lines?: bool, indexes?: bool} $usedAttributes
* @param array{lines?: bool, indexes?: bool, comments?: bool} $usedAttributes
*/
public function __construct(array $usedAttributes)
{
$this->useLinesAttributes = $usedAttributes['lines'] ?? \false;
$this->useIndexAttributes = $usedAttributes['indexes'] ?? \false;
$this->useCommentsAttributes = $usedAttributes['comments'] ?? \false;
}
}

View File

@ -5,6 +5,7 @@ namespace PHPStan\PhpDocParser\Printer;
use LogicException;
use PHPStan\PhpDocParser\Ast\Attribute;
use PHPStan\PhpDocParser\Ast\Comment;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
use PHPStan\PhpDocParser\Ast\Node;
@ -67,6 +68,7 @@ use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use function array_keys;
use function array_map;
use function assert;
use function count;
use function get_class;
use function get_object_vars;
@ -75,6 +77,7 @@ use function in_array;
use function is_array;
use function preg_match_all;
use function sprintf;
use function str_replace;
use function strlen;
use function strpos;
use function trim;
@ -415,20 +418,24 @@ final class Printer
}
foreach ($diff as $i => $diffElem) {
$diffType = $diffElem->type;
$newNode = $diffElem->new;
$originalNode = $diffElem->old;
$arrItem = $diffElem->new;
$origArrayItem = $diffElem->old;
if ($diffType === \PHPStan\PhpDocParser\Printer\DiffElem::TYPE_KEEP || $diffType === \PHPStan\PhpDocParser\Printer\DiffElem::TYPE_REPLACE) {
$beforeFirstKeepOrReplace = \false;
if (!$newNode instanceof Node || !$originalNode instanceof Node) {
if (!$arrItem instanceof Node || !$origArrayItem instanceof Node) {
return null;
}
/** @var int $itemStartPos */
$itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX);
$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);
/** @var int $itemEndPos */
$itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX);
$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);
if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) {
throw new LogicException();
}
$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];
$origComments = $origArrayItem->getAttribute(Attribute::COMMENTS) ?? [];
$commentStartPos = count($origComments) > 0 ? $origComments[0]->startIndex : $itemStartPos;
assert($commentStartPos >= 0);
$result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos);
if (count($delayedAdd) > 0) {
foreach ($delayedAdd as $delayedAddNode) {
@ -436,6 +443,13 @@ final class Printer
if ($parenthesesNeeded) {
$result .= '(';
}
if ($insertNewline) {
$delayedAddComments = $delayedAddNode->getAttribute(Attribute::COMMENTS) ?? [];
if (count($delayedAddComments) > 0) {
$result .= $this->printComments($delayedAddComments, $beforeAsteriskIndent, $afterAsteriskIndent);
$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
}
}
$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
if ($parenthesesNeeded) {
$result .= ')';
@ -448,12 +462,18 @@ final class Printer
}
$delayedAdd = [];
}
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], \true) && !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], \true);
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], \true) && !in_array(get_class($origArrayItem), $this->parenthesesListMap[$mapKey], \true);
$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos);
if ($addParentheses) {
$result .= '(';
}
$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
if ($comments !== $origComments) {
if (count($comments) > 0) {
$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);
$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
}
}
$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);
if ($addParentheses) {
$result .= ')';
}
@ -462,42 +482,48 @@ final class Printer
if ($insertStr === null) {
return null;
}
if (!$newNode instanceof Node) {
if (!$arrItem instanceof Node) {
return null;
}
if ($insertStr === ', ' && $isMultiline) {
if ($insertStr === ', ' && $isMultiline || count($arrItem->getAttribute(Attribute::COMMENTS) ?? []) > 0) {
$insertStr = ',';
$insertNewline = \true;
}
if ($beforeFirstKeepOrReplace) {
// Will be inserted at the next "replace" or "keep" element
$delayedAdd[] = $newNode;
$delayedAdd[] = $arrItem;
continue;
}
/** @var int $itemEndPos */
$itemEndPos = $tokenIndex - 1;
if ($insertNewline) {
$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];
$result .= $insertStr;
if (count($comments) > 0) {
$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);
}
$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
} else {
$result .= $insertStr;
}
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], \true);
$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], \true);
if ($parenthesesNeeded) {
$result .= '(';
}
$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);
if ($parenthesesNeeded) {
$result .= ')';
}
$tokenIndex = $itemEndPos + 1;
} elseif ($diffType === \PHPStan\PhpDocParser\Printer\DiffElem::TYPE_REMOVE) {
if (!$originalNode instanceof Node) {
if (!$origArrayItem instanceof Node) {
return null;
}
/** @var int $itemStartPos */
$itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX);
$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);
/** @var int $itemEndPos */
$itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX);
$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);
if ($itemStartPos < 0 || $itemEndPos < 0) {
throw new LogicException();
}
@ -547,6 +573,17 @@ final class Printer
}
return $result;
}
/**
* @param list<Comment> $comments
*/
private function printComments(array $comments, string $beforeAsteriskIndent, string $afterAsteriskIndent) : string
{
$formattedComments = [];
foreach ($comments as $comment) {
$formattedComments[] = str_replace("\n", "\n" . $beforeAsteriskIndent . '*' . $afterAsteriskIndent, $comment->getReformattedText());
}
return implode("\n{$beforeAsteriskIndent}*{$afterAsteriskIndent}", $formattedComments);
}
/**
* @param array<Node|null> $nodes
* @return array{bool, string, string}
@ -574,7 +611,7 @@ final class Printer
}
$c = preg_match_all('~\\n(?<before>[\\x09\\x20]*)\\*(?<after>\\x20*)~', $allText, $matches, PREG_SET_ORDER);
if ($c === 0) {
return [$isMultiline, '', ''];
return [$isMultiline, ' ', ' '];
}
$before = '';
$after = '';
@ -587,6 +624,8 @@ final class Printer
}
$after = $match['after'];
}
$before = strlen($before) === 0 ? ' ' : $before;
$after = strlen($after) === 0 ? ' ' : $after;
return [$isMultiline, $before, $after];
}
private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens) : string

View File

@ -30,7 +30,7 @@ if (!function_exists('humbug_phpscoper_expose_class')) {
}
}
humbug_phpscoper_expose_class('AutoloadIncluder', 'RectorPrefix202502\AutoloadIncluder');
humbug_phpscoper_expose_class('ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23', 'RectorPrefix202502\ComposerAutoloaderInita9ca9624b9ec3b7183135fb9d7d95d23');
humbug_phpscoper_expose_class('ComposerAutoloaderInit30bd5d3b9b1d532a1d3e11eb20f91e28', 'RectorPrefix202502\ComposerAutoloaderInit30bd5d3b9b1d532a1d3e11eb20f91e28');
humbug_phpscoper_expose_class('Product', 'RectorPrefix202502\Product');
humbug_phpscoper_expose_class('SomeTest', 'RectorPrefix202502\SomeTest');