Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
print comments
  • Loading branch information
ondrejmirtes committed Feb 19, 2025
commit d9523d9d10dbf3926730c5cba030640c356d6cab
17 changes: 9 additions & 8 deletions src/Ast/Comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@

use function trim;

class Comment
class Comment implements Node
{

public string $text;

public int $startLine;
use NodeAttributes;

public int $startIndex;
public string $text;

public function __construct(string $text, int $startLine = -1, int $startIndex = -1)
public function __construct(string $text)
{
$this->text = $text;
$this->startLine = $startLine;
$this->startIndex = $startIndex;
}

public function getReformattedText(): string
{
return trim($this->text);
}

public function __toString(): string
{
return $this->getReformattedText();
}

}
25 changes: 23 additions & 2 deletions src/Parser/TokenIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PHPStan\PhpDocParser\Parser;

use LogicException;
use PHPStan\PhpDocParser\Ast\Attribute;
use PHPStan\PhpDocParser\Ast\Comment;
use PHPStan\PhpDocParser\Lexer\Lexer;
use function array_pop;
Expand Down Expand Up @@ -232,8 +233,18 @@ public function skipNewLineTokens(): void
public function skipNewLineTokensAndConsumeComments(): void
{
if ($this->currentTokenType() === Lexer::TOKEN_COMMENT) {
$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
$startLine = $this->currentTokenLine();
$startIndex = $this->currentTokenIndex();
$text = $this->currentTokenValue();

$this->next();

$c = new Comment($text);
$c->setAttribute(Attribute::START_LINE, $startLine);
$c->setAttribute(Attribute::START_INDEX, $startIndex);
$c->setAttribute(Attribute::END_LINE, $this->currentTokenLine());
$c->setAttribute(Attribute::END_INDEX, $this->currentTokenIndex());
$this->comments[] = $c;
}

if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
Expand All @@ -246,8 +257,18 @@ public function skipNewLineTokensAndConsumeComments(): void
continue;
}

$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
$startLine = $this->currentTokenLine();
$startIndex = $this->currentTokenIndex();
$text = $this->currentTokenValue();

$this->next();

$c = new Comment($text);
$c->setAttribute(Attribute::START_LINE, $startLine);
$c->setAttribute(Attribute::START_INDEX, $startIndex);
$c->setAttribute(Attribute::END_LINE, $this->currentTokenLine());
$c->setAttribute(Attribute::END_INDEX, $this->currentTokenIndex());
$this->comments[] = $c;
} while ($foundNewLine === true);
}

Expand Down
94 changes: 59 additions & 35 deletions src/Printer/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
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;
Expand Down Expand Up @@ -113,6 +112,7 @@ final class Printer
MethodTagValueNode::class . '->parameters' => ', ',
DoctrineArray::class . '->items' => ', ',
DoctrineAnnotation::class . '->arguments' => ', ',
Comment::class . '->commentsAttribute' => "\n * ",
];

/**
Expand Down Expand Up @@ -196,7 +196,7 @@ public function print(Node $node): string
return "/**\n *" . implode("\n *", array_map(
function (PhpDocChildNode $child): string {
$s = $this->print($child);
return $s === '' ? '' : ' ' . $s;
return $s === '' ? '' : ' ' . str_replace("\n", "\n * ", $s);
},
$node->children,
)) . "\n */";
Expand All @@ -214,31 +214,38 @@ function (PhpDocChildNode $child): string {
if ($node instanceof PhpDocTagValueNode) {
return $this->printTagValue($node);
}

$comments = $node->getAttribute(Attribute::COMMENTS) ?? [];
$printedComments = '';
if ($comments !== []) {
$printedComments = implode("\n", array_map(static fn (Comment $comment) => $comment->getReformattedText(), $comments)) . "\n";
}

if ($node instanceof TypeNode) {
return $this->printType($node);
return $printedComments . $this->printType($node);
}
if ($node instanceof ConstExprNode) {
return $this->printConstExpr($node);
return $printedComments . $this->printConstExpr($node);
}
if ($node instanceof MethodTagValueParameterNode) {
$type = $node->type !== null ? $this->print($node->type) . ' ' : '';
$isReference = $node->isReference ? '&' : '';
$isVariadic = $node->isVariadic ? '...' : '';
$default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : '';
return "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}";
return $printedComments . "{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}";
}
if ($node instanceof CallableTypeParameterNode) {
$type = $this->print($node->type) . ' ';
$isReference = $node->isReference ? '&' : '';
$isVariadic = $node->isVariadic ? '...' : '';
$isOptional = $node->isOptional ? '=' : '';
return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
return $printedComments . trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
}
if ($node instanceof ArrayShapeUnsealedTypeNode) {
if ($node->keyType !== null) {
return sprintf('<%s, %s>', $this->print($node->keyType), $this->print($node->valueType));
return $printedComments . sprintf('<%s, %s>', $this->print($node->keyType), $this->print($node->valueType));
}
return sprintf('<%s>', $this->print($node->valueType));
return $printedComments . sprintf('<%s>', $this->print($node->valueType));
}
if ($node instanceof DoctrineAnnotation) {
return (string) $node;
Expand All @@ -254,27 +261,31 @@ function (PhpDocChildNode $child): string {
}
if ($node instanceof ArrayShapeItemNode) {
if ($node->keyName !== null) {
return sprintf(
return $printedComments . sprintf(
'%s%s: %s',
$this->print($node->keyName),
$node->optional ? '?' : '',
$this->print($node->valueType),
);
}

return $this->print($node->valueType);
return $printedComments . $this->print($node->valueType);
}
if ($node instanceof ObjectShapeItemNode) {
if ($node->keyName !== null) {
return sprintf(
return $printedComments . sprintf(
'%s%s: %s',
$this->print($node->keyName),
$node->optional ? '?' : '',
$this->print($node->valueType),
);
}

return $this->print($node->valueType);
return $printedComments . $this->print($node->valueType);
}

if ($node instanceof Comment) {
return $node->getReformattedText();
}

throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
Expand Down Expand Up @@ -576,7 +587,7 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
if ($parenthesesNeeded) {
$result .= '(';
}
$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens, $beforeAsteriskIndent, $afterAsteriskIndent);
if ($parenthesesNeeded) {
$result .= ')';
}
Expand All @@ -599,7 +610,7 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
$result .= '(';
}

$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
$result .= $this->printNodeFormatPreserving($newNode, $originalTokens, $beforeAsteriskIndent, $afterAsteriskIndent);
if ($addParentheses) {
$result .= ')';
}
Expand Down Expand Up @@ -638,7 +649,7 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
$result .= '(';
}

$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
$result .= $this->printNodeFormatPreserving($newNode, $originalTokens, $beforeAsteriskIndent, $afterAsteriskIndent);
if ($parenthesesNeeded) {
$result .= ')';
}
Expand Down Expand Up @@ -703,7 +714,7 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
}
}

$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens, $beforeAsteriskIndent, $afterAsteriskIndent);
$first = false;
}
$result .= $extraRight;
Expand All @@ -712,18 +723,9 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
return $result;
}

/**
* @param list<Comment> $comments
*/
private function printComments(array $comments, string $beforeAsteriskIndent, string $afterAsteriskIndent): string
private function fixMultiline(string $s, 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);
return str_replace("\n", "\n" . $beforeAsteriskIndent . '*' . $afterAsteriskIndent, $s);
}

/**
Expand Down Expand Up @@ -777,12 +779,12 @@ private function isMultiline(int $initialIndex, array $nodes, TokenIterator $ori
return [$isMultiline, $before, $after];
}

private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens): string
private function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens, string $beforeAsteriskIndent, string $afterAsteriskIndent): string
{
/** @var Node|null $originalNode */
$originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE);
if ($originalNode === null) {
return $this->print($node);
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

$class = get_class($node);
Expand All @@ -797,6 +799,28 @@ private function printNodeFormatPreserving(Node $node, TokenIterator $originalTo
}

$result = '';

/** @var list<Comment> $comments */
$comments = $node->getAttribute(Attribute::COMMENTS) ?? [];

/** @var list<Comment> $originalComments */
$originalComments = $originalNode->getAttribute(Attribute::COMMENTS) ?? [];

$startPos = count($originalComments) > 0 ? $originalComments[0]->getAttribute(Attribute::START_INDEX) : $startPos;
$commentsResult = $this->printArrayFormatPreserving(
$comments,
$originalComments,
$originalTokens,
$startPos,
Comment::class,
'commentsAttribute',
);
if ($commentsResult === null) {
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

$result .= $commentsResult;

$pos = $startPos;
$subNodeNames = array_keys(get_object_vars($node));
foreach ($subNodeNames as $subNodeName) {
Expand Down Expand Up @@ -824,14 +848,14 @@ private function printNodeFormatPreserving(Node $node, TokenIterator $originalTo
);

if ($listResult === null) {
return $this->print($node);
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

$result .= $listResult;
continue;
}

return $this->print($node);
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

if ($origSubNode === null) {
Expand All @@ -840,7 +864,7 @@ private function printNodeFormatPreserving(Node $node, TokenIterator $originalTo
continue;
}

return $this->print($node);
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

$subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX);
Expand All @@ -850,11 +874,11 @@ private function printNodeFormatPreserving(Node $node, TokenIterator $originalTo
}

if ($subEndPos < $subStartPos) {
return $this->print($node);
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

if ($subNode === null) {
return $this->print($node);
return $this->fixMultiline($this->print($node), $beforeAsteriskIndent, $afterAsteriskIndent);
}

$result .= $originalTokens->getContentBetween($pos, $subStartPos);
Expand All @@ -872,7 +896,7 @@ private function printNodeFormatPreserving(Node $node, TokenIterator $originalTo
$result .= '(';
}

$result .= $this->printNodeFormatPreserving($subNode, $originalTokens);
$result .= $this->printNodeFormatPreserving($subNode, $originalTokens, $beforeAsteriskIndent, $afterAsteriskIndent);
if ($addParentheses) {
$result .= ')';
}
Expand Down
Loading