nikic / PHP-Parser

A PHP parser written in PHP
BSD 3-Clause "New" or "Revised" License
17.03k stars 1.1k forks source link

Parser does not see docComments between attributes and class declaration #762

Open ondrejmirtes opened 3 years ago

ondrejmirtes commented 3 years ago

Given this PHP code:

<?php

#[AttributeStub()]
/**
 * @template T
 */
class ClassStub
{
    /**
     * @param T $var
     */
    public function __construct(public $var) {}
}

PHP itself sees both attribute and doc comment: https://3v4l.org/Pe17n

But PHP-Parser doesn't (bin/php-parse output on PHP 7.4):

array(
    0: Stmt_Class(
        attrGroups: array(
            0: AttributeGroup(
                attrs: array(
                    0: Attribute(
                        name: Name(
                            parts: array(
                                0: AttributeStub
                            )
                        )
                        args: array(
                        )
                    )
                )
            )
        )
        flags: 0
        name: Identifier(
            name: ClassStub
        )
        extends: null
        implements: array(
        )
        stmts: array(
            0: Stmt_ClassMethod(
                attrGroups: array(
                )
                flags: MODIFIER_PUBLIC (1)
                byRef: false
                name: Identifier(
                    name: __construct
                )
                params: array(
                    0: Param(
                        attrGroups: array(
                        )
                        flags: MODIFIER_PUBLIC (1)
                        type: null
                        byRef: false
                        variadic: false
                        var: Expr_Variable(
                            name: var
                        )
                        default: null
                    )
                )
                returnType: null
                stmts: array(
                )
                comments: array(
                    0: /**
                     * @param T $var
                     */
                )
            )
        )
    )
)

Original report: https://github.com/phpstan/phpstan/issues/4633

nikic commented 3 years ago

The parser only collects comments before a node -- as the attributes are considered part of the class, the doc comment ends up being "inside" the class, and thus lost. It's not really possible to fix this with the current architecture.

ondrejmirtes commented 3 years ago

Alright, thanks! This is probably the same issue:

class HelloWorld
{
    #[Groups]
    #[Valid]
    /** @var \stdClass[]|null */
    public ?array $damages = null;
}
bwl21 commented 2 years ago

given this php code

        if (
            /** @authdoc-c (i18n="foobar") */
            !check("view", "foobar") &&
            /** @authdoc-c (i18n="barfoo") */
            (empty($myGroups[$groupId]) || !check($myGroups[$groupId], "barfoo"))
        )

the second docblock is not seen as well. I guess it is a similar problem.

vudaltsov commented 1 year ago

It seems to me, using $node->name->getStartLine() is the most reliable option right now. It's not always correct, because we can have

#[Attr]
final
class
A {}

But it's less likely than

#[Attr]
final class A {}