Skip to content

Commit 034afd3

Browse files
committed
Return name nodes for class names from Type::toPhpDocNode()
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
1 parent 2bf0ea5 commit 034afd3

21 files changed

Lines changed: 184 additions & 71 deletions

‎build/PHPStan/Build/TurboAttributeCollector.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode;
179179
use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode;
180180
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
181+
use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode;
181182
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
182183
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
183184
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
@@ -186,7 +187,6 @@
186187
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
187188
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
188189
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
189-
use PHPStan\PhpDocParser\Printer\Printer;
190190
use PHPStan\Turbo\ReferencedByTurboExtension;
191191
use PHPStan\Turbo\ShadowedByTurboExtension;
192192
use RecursiveDirectoryIterator;
@@ -264,6 +264,7 @@ final class TurboAttributeCollector
264264
'closureExpr' => Closure::class,
265265
'arrowFunction' => ArrowFunction::class,
266266
'identifierTypeNode' => IdentifierTypeNode::class,
267+
'fullyQualifiedNameNode' => FullyQualifiedNameNode::class,
267268
'genericTypeNode' => GenericTypeNode::class,
268269
'constTypeNode' => ConstTypeNode::class,
269270
'constExprIntegerNode' => ConstExprIntegerNode::class,
@@ -275,7 +276,6 @@ final class TurboAttributeCollector
275276
'objectShapeNode' => ObjectShapeNode::class,
276277
'objectShapeItemNode' => ObjectShapeItemNode::class,
277278
'constFetchNode' => ConstFetchNode::class,
278-
'phpDocPrinter' => Printer::class,
279279
'callableTypeNode' => CallableTypeNode::class,
280280
'callableTypeParameterNode' => CallableTypeParameterNode::class,
281281
'templateTagValueNode' => TemplateTagValueNode::class,

‎src/Type/CallableType.php‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
1313
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
1414
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
15-
use PHPStan\PhpDocParser\Printer\Printer;
1615
use PHPStan\Reflection\Assertions;
1716
use PHPStan\Reflection\Callables\CallableParametersAcceptor;
1817
use PHPStan\Reflection\Callables\SimpleImpurePoint;
@@ -337,7 +336,6 @@ public function describe(VerbosityLevel $level): string
337336
return $level->handle(
338337
static fn (): string => 'callable',
339338
function (): string {
340-
$printer = new Printer();
341339
$assertedParameterNames = [];
342340
foreach ($this->assertions->getAll() as $assertTag) {
343341
$assertedParameterNames[$assertTag->getParameter()->getParameterName()] = true;
@@ -360,7 +358,7 @@ function (): string {
360358
$this->assertions,
361359
);
362360

363-
return $printer->print($selfWithoutParameterNames->toPhpDocNode());
361+
return TypeNodeDescriber::describe($selfWithoutParameterNames->toPhpDocNode());
364362
},
365363
);
366364
}

‎src/Type/ClosureType.php‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
1212
use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
1313
use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
14+
use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode;
1415
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
1516
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
16-
use PHPStan\PhpDocParser\Printer\Printer;
1717
use PHPStan\Reflection\Assertions;
1818
use PHPStan\Reflection\Callables\CallableParametersAcceptor;
1919
use PHPStan\Reflection\Callables\SimpleImpurePoint;
@@ -352,7 +352,6 @@ function (): string {
352352

353353
private function describeCallable(): string
354354
{
355-
$printer = new Printer();
356355
$assertedParameterNames = [];
357356
foreach ($this->assertions->getAll() as $assertTag) {
358357
$assertedParameterNames[$assertTag->getParameter()->getParameterName()] = true;
@@ -382,7 +381,7 @@ private function describeCallable(): string
382381
$this->isStatic,
383382
);
384383

385-
return $printer->print($selfWithoutParameterNames->toPhpDocNode());
384+
return TypeNodeDescriber::describe($selfWithoutParameterNames->toPhpDocNode());
386385
}
387386

388387
public function isOffsetAccessLegal(): TrinaryLogic
@@ -997,6 +996,10 @@ public function toPhpDocNode(): TypeNode
997996
{
998997
if ($this->isCommonCallable) {
999998
$prefix = $this->isStatic->yes() ? 'static-' : '';
999+
if ($prefix === '' && !$this->isPure()->yes()) {
1000+
return new FullyQualifiedNameNode(Closure::class);
1001+
}
1002+
10001003
$name = $this->isPure()->yes() ? 'pure-Closure' : 'Closure';
10011004
return new IdentifierTypeNode($prefix . $name);
10021005
}
@@ -1025,7 +1028,7 @@ public function toPhpDocNode(): TypeNode
10251028
?? $this->returnType->toPhpDocNode();
10261029

10271030
return new CallableTypeNode(
1028-
new IdentifierTypeNode('Closure'),
1031+
new FullyQualifiedNameNode(Closure::class),
10291032
$parameters,
10301033
$returnTypeNode,
10311034
$templateTags,

‎src/Type/Enum/EnumCaseObjectType.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public function toPhpDocNode(): TypeNode
250250
{
251251
return new ConstTypeNode(
252252
new ConstFetchNode(
253-
$this->getClassName(),
253+
'\\' . $this->getClassName(),
254254
$this->getEnumCaseName(),
255255
),
256256
);

‎src/Type/Generic/GenericObjectType.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
namespace PHPStan\Type\Generic;
44

5+
use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode;
56
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
6-
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
77
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
88
use PHPStan\Reflection\ClassMemberAccessAnswerer;
99
use PHPStan\Reflection\ClassReflection;
@@ -454,7 +454,7 @@ public function changeSubtractedType(?Type $subtractedType): Type
454454

455455
public function toPhpDocNode(): TypeNode
456456
{
457-
/** @var IdentifierTypeNode $parent */
457+
/** @var FullyQualifiedNameNode $parent */
458458
$parent = parent::toPhpDocNode();
459459
return new GenericTypeNode(
460460
$parent,

‎src/Type/Helper/GetTemplateTypeType.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
66
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
7+
use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode;
78
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
89
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
910
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
@@ -99,7 +100,7 @@ public function toPhpDocNode(): TypeNode
99100
new IdentifierTypeNode('template-type'),
100101
[
101102
$this->type->toPhpDocNode(),
102-
new IdentifierTypeNode($this->ancestorClassName),
103+
new FullyQualifiedNameNode($this->ancestorClassName),
103104
new ConstTypeNode(new ConstExprStringNode($this->templateTypeName, ConstExprStringNode::SINGLE_QUOTED)),
104105
],
105106
);

‎src/Type/LateResolvableArrayShapeType.php‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
1212
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
1313
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
14-
use PHPStan\PhpDocParser\Printer\Printer;
1514
use PHPStan\ShouldNotHappenException;
1615
use PHPStan\Turbo\ShadowedByTurboExtension;
1716
use PHPStan\Type\Accessory\AccessoryArrayListType;
@@ -171,7 +170,7 @@ public function equals(Type $type): bool
171170
public function describe(VerbosityLevel $level): string
172171
{
173172
// a shape that can be resolved never stays late-resolvable, see create()
174-
return (new Printer())->print($this->toPhpDocNode());
173+
return TypeNodeDescriber::describe($this->toPhpDocNode());
175174
}
176175

177176
public function isResolvable(): bool

‎src/Type/ObjectType.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use PHPStan\Broker\ClassNotFoundException;
1515
use PHPStan\Internal\LruCache;
1616
use PHPStan\Php\PhpVersion;
17-
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
17+
use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode;
1818
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
1919
use PHPStan\Reflection\Callables\CallableParametersAcceptor;
2020
use PHPStan\Reflection\Callables\FunctionCallableVariant;
@@ -2131,7 +2131,7 @@ public function exponentiate(Type $exponent): Type
21312131

21322132
public function toPhpDocNode(): TypeNode
21332133
{
2134-
return new IdentifierTypeNode($this->getClassName());
2134+
return new FullyQualifiedNameNode($this->getClassName());
21352135
}
21362136

21372137
public function toNativePhpTypeNode(NativeTypePosition $position)

‎src/Type/OffsetAccessType.php‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
66
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7-
use PHPStan\PhpDocParser\Printer\Printer;
87
use PHPStan\Turbo\ShadowedByTurboExtension;
98
use PHPStan\Type\Generic\TemplateTypeVariance;
109
use PHPStan\Type\Traits\LateResolvableTypeTrait;
@@ -61,9 +60,7 @@ public function equals(Type $type): bool
6160

6261
public function describe(VerbosityLevel $level): string
6362
{
64-
$printer = new Printer();
65-
66-
return $printer->print($this->toPhpDocNode());
63+
return TypeNodeDescriber::describe($this->toPhpDocNode());
6764
}
6865

6966
public function isResolvable(): bool

‎src/Type/TypeNodeDescriber.php‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type;
4+
5+
use Override;
6+
use PHPStan\PhpDocParser\Ast\AbstractNodeVisitor;
7+
use PHPStan\PhpDocParser\Ast\Node;
8+
use PHPStan\PhpDocParser\Ast\NodeTraverser;
9+
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
10+
use PHPStan\PhpDocParser\Ast\Type\NameNode;
11+
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
12+
use PHPStan\PhpDocParser\Printer\Printer;
13+
use PHPStan\Turbo\ReferencedByTurboExtension;
14+
15+
/**
16+
* Prints a PHPDoc type node for describe(): class names without the leading
17+
* backslash, as everywhere else in PHPStan's type descriptions.
18+
*/
19+
#[ReferencedByTurboExtension(key: 'typeNodeDescriber')]
20+
final class TypeNodeDescriber
21+
{
22+
23+
private static ?NodeTraverser $traverser = null;
24+
25+
private static ?Printer $printer = null;
26+
27+
public static function describe(TypeNode $typeNode): string
28+
{
29+
self::$traverser ??= new NodeTraverser([
30+
new class () extends AbstractNodeVisitor {
31+
32+
#[Override]
33+
public function enterNode(Node $node): ?Node
34+
{
35+
if ($node instanceof NameNode) {
36+
return new IdentifierTypeNode($node->toString());
37+
}
38+
39+
return null;
40+
}
41+
42+
},
43+
]);
44+
self::$printer ??= new Printer();
45+
[$typeNode] = self::$traverser->traverse([$typeNode]);
46+
47+
return self::$printer->print($typeNode);
48+
}
49+
50+
}

0 commit comments

Comments
 (0)