Skip to content

Return phpdoc-parser name nodes for class names from Type::toPhpDocNode() - #6875

Merged
ondrejmirtes merged 2 commits into
2.3.xfrom
phpdoc-name-nodes
Oct 28, 2026
Merged

ondrejmirtes merged 2 commits into
2.3.xfrom
phpdoc-name-nodes

Conversation

@ondrejmirtes

@ondrejmirtes ondrejmirtes commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Type::toPhpDocNode() returned a plain IdentifierTypeNode for both keywords (int, mixed, non-falsy-string) and class names, so consumers had to guess which was which and how to print or import it.

This now uses phpdoc-parser 2.4's NameNode, FullyQualifiedNameNode and RelativeNameNode (phpstan/phpdoc-parser#339, pulled in by #6877). They don't extend IdentifierTypeNode, so PHPStan doesn't ship its own copies any more.

Commit 1: handle name nodes when resolving PHPDocs. With phpdoc-parser 2.4, 2.3.x currently has 7 make phpstan errors where code reads ->name from a node that can now be a NameNode. This commit fixes them:

  • TypeNodeResolver resolves a name node as a class against the name scope, before keywords, type aliases and template types. A RelativeNameNode('Int') in namespace App is the class App\Int, while IdentifierTypeNode('Int') is still int.
  • PhpDocNodeResolver (@extends, @implements, @use, @phpstan-import-type) and IntersectionType::toPhpDocNode() (PHP and turbo) no longer assume an IdentifierTypeNode.

Commit 2: return name nodes from toPhpDocNode().

  • ObjectType, GenericObjectType, ClosureType and GetTemplateTypeType return FullyQualifiedNameNode, and EnumCaseObjectType a fully qualified ConstFetchNode. A printed node resolves to the same class in any namespace and with any uses. Keywords, pure-/static-Closure and template type names stay IdentifierTypeNode.
  • describe() output is unchanged: TypeNodeDescriber prints names without the leading backslash. That also covers OffsetAccessType and LateResolvableArrayShapeType.
  • The turbo extension returns the same nodes. The now-unused Printer class ref is gone; fullyQualifiedNameNode is a new one.

Rector counterpart (local prototype, not opened yet): with these nodes Rector can delete its whole PHPStanStaticTypeMapper package (all 30 mapToPHPStanPhpDocTypeNode() mappers), about −1750 lines, with its full test suite green after a small style pass and 14 fixtures with equivalent output.

phpdoc-parser 2.4 adds FullyQualifiedNameNode and RelativeNameNode for
class names. They do not extend IdentifierTypeNode, and
GenericTypeNode::$type, CallableTypeNode::$identifier and
TypeAliasImportTagValueNode::$importedFrom can now hold them.

TypeNodeResolver resolves a name node as a class against the name scope,
before keywords, type aliases and template types are considered, so a
RelativeNameNode named Int or T is a class, not int or a template type.
The tag resolvers and IntersectionType::toPhpDocNode() no longer assume
an IdentifierTypeNode there.

Amp-Thread-ID: https://ampcode.com/threads/T-01a179f2-995f-7745-8d8c-4c174ba5c0ce
Type::toPhpDocNode() returned a plain IdentifierTypeNode for both
keywords (int, mixed, non-falsy-string) and class names, so consumers
like Rector had to guess which is which and how to print it.

ObjectType, GenericObjectType, ClosureType and GetTemplateTypeType now
return phpdoc-parser's FullyQualifiedNameNode, and EnumCaseObjectType a
fully qualified ConstFetchNode, so a printed node resolves to the same
class in any namespace. Keywords, pure-/static-Closure and template
type names stay IdentifierTypeNode.

describe() output is unchanged: TypeNodeDescriber prints names without
the leading backslash. The turbo extension returns the same nodes.

Amp-Thread-ID: https://ampcode.com/threads/T-01a179f2-995f-7745-8d8c-4c174ba5c0ce
@ondrejmirtes ondrejmirtes changed the title Add PHPDoc name nodes for class names in Type::toPhpDocNode() Return phpdoc-parser name nodes for class names from Type::toPhpDocNode() Oct 28, 2026
@ondrejmirtes
ondrejmirtes merged commit 034afd3 into 2.3.x Oct 28, 2026
1024 of 1033 checks passed
@ondrejmirtes
ondrejmirtes deleted the phpdoc-name-nodes branch October 28, 2026 21:47
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.

1 participant