Skip to content

fix: don't duplicate comments in short-form if blocks and after open tags - #2548

Open
marqu3s wants to merge 1 commit into
prettier:mainfrom
marqu3s:fix/short-form-if-body-loc
Open

marqu3s wants to merge 1 commit into
prettier:mainfrom
marqu3s:fix/short-form-if-body-loc

Conversation

@marqu3s

@marqu3s marqu3s commented Oct 23, 2026 •

Copy link
Copy Markdown

Fixes #1705
Fixes #2495

Comments in templates that mix PHP and inline HTML were duplicated, and the copies grew on every run (1 → 2 → 4 → 8), which is painful with format-on-save. Two separate causes:

1. Short-form if with else: / elseif:

php-parser ends the body of a short-form if where the whole statement ends, so the body overlaps the alternate:

if    [6,143]
 body      block [13,131]   <- should end at its last child (31)
 alternate block [41,131]

Any comment inside the else:/elseif: branch is then inside both blocks. It ended up as a dangling comment of the if, printed twice and moved before else:. parse() now ends the body at its last child, and the comment stays where it was written.

<?php if ($a): ?>
    <p>x</p>
<?php else: ?>
    <?php
    $h = 1;
    // comment
    $g = 2;
    ?>
<?php endif; ?>

Before (one run):

<?php
    // comment
    // comment
    else: ?>
    <?php
    $h = 1;
    $g = 2;
    ?>

After: unchanged.

2. Comment right after an open tag that follows inline HTML

<div>
    <?php // comment
    $a = 1; ?>
</div>

This became a trailing comment of the inline node. printLines() prints inline.comments itself and prettier prints it again, so it was duplicated. handleInlineComments now makes it a leading comment of the next statement. This is where the plugin already puts an own-line comment in the same spot (<?php\n// comment\n$a = 1; is formatted as <?php // comment\n$a = 1;), so the second run is stable too.

Tests

  • New fixtures: tests/comments/inline-short-form-if.php, inline-short-form-elseif.php, inline-open-tag-comment.php. On main they print every comment twice on the first run.
  • One existing snapshot changes, comments/inline9.php: the blank line between <?php //BAR and echo "bar" goes away and the statement keeps the block indentation.
  • yarn test, AST_COMPARE=1 yarn test:node and yarn lint pass.
  • I also checked 140 combinations (#, //, /* */ and /** */, at different positions inside if:/else:/elseif:/foreach:/plain HTML) with 3 runs each. All are stable now; on main, 35 of them duplicated.

Not covered

#1228 (?>\n<?php with nothing between) is a different issue. It comes from the ___PSEUDO_INLINE_PLACEHOLDER___ workaround in parse(): node locations then refer to the text with the placeholder, not to the original text. Comments after such a placeholder can be misclassified (for example, an own-line comment printed at the end of the previous line). This PR does not touch that.

🤖 Generated with Claude Code

…tags

- php-parser ends the body of a short-form `if` (`if (): ... else: ...
  endif;`) where the whole statement ends, so it overlaps the alternate and
  comments inside the `else:`/`elseif:` branch were printed twice (and once
  more on every run). The body now ends at its last child.
- A comment right after an open tag that follows inline HTML
  (`<div><?php // comment`) was attached as a trailing comment of the inline
  node and printed twice. It is now a leading comment of the next statement.

Fixes prettier#1705
Fixes prettier#2495

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prettier duplicates a comment and inserts it somewhere else Comments duplicating out of scope

1 participant