Printer drops the `*` prefix on continuation lines of a changed multi-line PhpDocTextNode

Đang mở
#317 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
68/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
php
Lĩnh vực
tooling

Hướng nghiên cứu

Start with PhpDocParser::parseText(), Printer::print(), printNodeFormatPreserving(), and printArrayFormatPreserving(), using the reproduction in the issue to trace how continuation-line prefixes are lost. Ensure both printer paths preserve the asterisk indentation for changed multi-line text and tag values, matching the expected output shown for each path.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Printer::printFormatPreserving() and Printer::print() both emit a multi-line PhpDocTextNode verbatim. PhpDocParser::parseText() joins continuation lines with a bare \n and strips the * prefix, so any text node with more than one line prints as invalid docblock formatting as soon as it is not reused from the original tokens.

Reproduction

phpdoc-parser 2.3.5, PHP 8.5.

<?php declare(strict_types = 1);

use PHPStan\PhpDocParser\Ast\AbstractNodeVisitor;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeTraverser;
use PHPStan\PhpDocParser\Ast\NodeVisitor\CloningVisitor;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
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 PHPStan\PhpDocParser\ParserConfig;
use PHPStan\PhpDocParser\Printer\Printer;

require __DIR__ . '/vendor/autoload.php';

$config = new ParserConfig(['lines' => true, 'indexes' => true]);
$lexer = new Lexer($config);
$constExprParser = new ConstExprParser($config);
$parser = new PhpDocParser($config, new TypeParser($config, $constExprParser), $constExprParser);

$doc = <<<'DOC'
/**
     * First line Foo
     * second line Foo
     *
     * @param int $a
     */
DOC;

$tokens = $lexer->tokenize($doc);
$ast = $parser->parse(new TokenIterator($tokens));

$visitor = new class extends AbstractNodeVisitor {
    public function enterNode(Node $node): ?Node
    {
        if ($node instanceof PhpDocTextNode) {
            $node->text = str_replace('Foo', 'Bar', $node->text);
        }
        return null;
    }
};

[$newAst] = (new NodeTraverser([new CloningVisitor(), $visitor]))->traverse([$ast]);

$printer = new Printer();
echo $printer->printFormatPreserving($newAst, $ast, new TokenIterator($tokens)), "\n\n";
echo $printer->print($newAst), "\n";
Actual output
/**
     * First line Bar
second line Bar
     *
     * @param int $a
     */

/**
 * First line Bar
second line Bar
 *
 * @param int $a
 */
Expected output
/**
     * First line Bar
     * second line Bar
     *
     * @param int $a
     */

/**
 * First line Bar
 * second line Bar
 *
 * @param int $a
 */
Cause
  • PhpDocParser::parseText() appends $tokens->getDetectedNewline() ?? "\n" between continuation lines and drops the * prefix, so PhpDocTextNode::$text is "First line Foo\nsecond line Foo".
  • Printer::print() returns $node->text for a PhpDocTextNode as is. printNodeFormatPreserving() falls back to print() when a non-node sub-node such as $text changed, so the format-preserving path has the same result.
  • printArrayFormatPreserving() already computes $beforeAsteriskIndent and $afterAsteriskIndent via isMultiline() for inserted nodes, but does not apply them to newlines inside a printed child.

The same applies to multi-line description strings in GenericTagValueNode, ParamTagValueNode, DeprecatedTagValueNode and the other tag value nodes, which also hold bare \n.

Suggested fix

Re-insert the line prefix at every newline inside a printed child. In print() the prefix is "\n * ". In the format-preserving path it is newline . $beforeAsteriskIndent . '*' . $afterAsteriskIndent, which printArrayFormatPreserving() already has in scope. PR follows.

Claude

Ngôn ngữ chính
PHP
Star
1.5k
Fork
78
Merge trung bình
9 giờ 5 phút
Pull request đã merge (30 ngày)
5

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của phpstan/phpdoc-parser

Tất cả issue của phpstan/phpdoc-parser

Issue tương tự

Thêm issue về PHP

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.