Skip to content

Commit 88113ca

Browse files
committed
Context aware fqsen resolving on parameters
1 parent d5aea24 commit 88113ca

File tree

6 files changed

+64
-59
lines changed

6 files changed

+64
-59
lines changed

src/phpDocumentor/Reflection/Php/Expression/ExpressionPrinter.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
namespace phpDocumentor\Reflection\Php\Expression;
1515

1616
use phpDocumentor\Reflection\Fqsen;
17+
use phpDocumentor\Reflection\FqsenResolver;
1718
use phpDocumentor\Reflection\Php\Expression;
1819
use phpDocumentor\Reflection\Type;
20+
use phpDocumentor\Reflection\Types\Context;
1921
use PhpParser\Node\Expr;
2022
use PhpParser\Node\Name;
2123
use PhpParser\PrettyPrinter\Standard;
@@ -24,6 +26,16 @@ final class ExpressionPrinter extends Standard
2426
{
2527
/** @var array<string, Fqsen|Type> */
2628
private array $parts = [];
29+
private Context|null $context = null;
30+
private FqsenResolver $fqsenResolver;
31+
32+
/** {@inheritDoc} */
33+
public function __construct(array $options = [])
34+
{
35+
parent::__construct($options);
36+
37+
$this->fqsenResolver = new FqsenResolver();
38+
}
2739

2840
protected function resetState(): void
2941
{
@@ -32,11 +44,18 @@ protected function resetState(): void
3244
$this->parts = [];
3345
}
3446

47+
public function prettyPrintExpr(Expr $node, Context|null $context = null): string
48+
{
49+
$this->context = $context;
50+
51+
return parent::prettyPrintExpr($node);
52+
}
53+
3554
protected function pName(Name $node): string
3655
{
37-
$renderedName = parent::pName($node);
38-
$placeholder = Expression::generatePlaceholder($renderedName);
39-
$this->parts[$placeholder] = new Fqsen('\\' . $renderedName);
56+
$renderedName = $this->fqsenResolver->resolve(parent::pName($node), $this->context);
57+
$placeholder = Expression::generatePlaceholder((string) $renderedName);
58+
$this->parts[$placeholder] = $renderedName;
4059

4160
return $placeholder;
4261
}
@@ -56,7 +75,7 @@ protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node): string
5675
{
5776
$renderedName = parent::pObjectProperty($node->name);
5877
$className = $node->class instanceof Name ? parent::pName($node->class) : $this->p($node->class);
59-
$placeholder = Expression::generatePlaceholder($renderedName);
78+
$placeholder = Expression::generatePlaceholder((string) $renderedName);
6079
$this->parts[$placeholder] = new Fqsen(
6180
'\\' . $className . '::' . $renderedName,
6281
);

src/phpDocumentor/Reflection/Php/Factory/PropertyBuilder.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use phpDocumentor\Reflection\Php\PropertyHook;
1717
use phpDocumentor\Reflection\Php\StrategyContainer;
1818
use phpDocumentor\Reflection\Php\Visibility;
19+
use phpDocumentor\Reflection\Types\Context;
1920
use PhpParser\Comment\Doc;
2021
use PhpParser\Modifiers;
2122
use PhpParser\Node;
@@ -163,7 +164,7 @@ public function build(ContextStack $context): PropertyElement
163164
$this->fqsen,
164165
$this->visibility,
165166
$this->docblock !== null ? $this->docBlockFactory->create($this->docblock->getText(), $context->getTypeContext()) : null,
166-
$this->determineDefault(),
167+
$this->determineDefault($context->getTypeContext()),
167168
$this->static,
168169
$this->startLocation,
169170
$this->endLocation,
@@ -346,9 +347,14 @@ private function buildHookVisibility(string $hookName, Visibility $propertyVisib
346347
};
347348
}
348349

349-
private function determineDefault(): Expression|null
350+
private function determineDefault(Context|null $context): Expression|null
350351
{
351-
$expression = $this->default !== null ? $this->valueConverter->prettyPrintExpr($this->default) : null;
352+
if ($this->valueConverter instanceof ExpressionPrinter) {
353+
$expression = $this->default !== null ? $this->valueConverter->prettyPrintExpr($this->default, $context) : null;
354+
} else {
355+
$expression = $this->default !== null ? $this->valueConverter->prettyPrintExpr($this->default) : null;
356+
}
357+
352358
if ($expression === null) {
353359
return null;
354360
}

src/phpDocumentor/Reflection/Php/Factory/Reducer/Parameter.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use phpDocumentor\Reflection\Php\Method;
1515
use phpDocumentor\Reflection\Php\PropertyHook;
1616
use phpDocumentor\Reflection\Php\StrategyContainer;
17+
use phpDocumentor\Reflection\Types\Context;
1718
use PhpParser\Node\Expr\Variable;
1819
use PhpParser\Node\FunctionLike;
1920
use PhpParser\Node\Param;
@@ -50,7 +51,7 @@ public function reduce(
5051
new ArgumentDescriptor(
5152
is_string($param->var->name) ? $param->var->name : $this->valueConverter->prettyPrintExpr($param->var->name),
5253
(new Type())->fromPhpParser($param->type),
53-
$this->determineDefault($param),
54+
$this->determineDefault($param, $context->getTypeContext()),
5455
$param->byRef,
5556
$param->variadic,
5657
),
@@ -60,9 +61,14 @@ public function reduce(
6061
return $carry;
6162
}
6263

63-
private function determineDefault(Param $value): Expression|null
64+
private function determineDefault(Param $value, Context|null $context): Expression|null
6465
{
65-
$expression = $value->default !== null ? $this->valueConverter->prettyPrintExpr($value->default) : null;
66+
if ($this->valueConverter instanceof ExpressionPrinter) {
67+
$expression = $value->default !== null ? $this->valueConverter->prettyPrintExpr($value->default, $context) : null;
68+
} else {
69+
$expression = $value->default !== null ? $this->valueConverter->prettyPrintExpr($value->default) : null;
70+
}
71+
6672
if ($expression === null) {
6773
return null;
6874
}

tests/integration/PHP8/ConstructorPromotionTest.php

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,27 @@ public function testArgumentsAreReadCorrectly() : void
5252

5353
$constructor = $this->expectedConstructorMethod();
5454
$constructor->addArgument(new Argument('name', new String_(), "'default name'"));
55-
$constructor->addArgument(new Argument('email', new Object_(new Fqsen('\\PHP8\\Email'))));
55+
$constructor->addArgument(
56+
new Argument(
57+
'email',
58+
new Object_(new Fqsen('\\PHP8\\Email')),
59+
new Expression(
60+
'new {{ PHPDOCc27b34d4d91bc4d52190708db8447e09 }}()',
61+
[
62+
'{{ PHPDOCc27b34d4d91bc4d52190708db8447e09 }}' => new Fqsen('\\PHP8\\Email'),
63+
],
64+
)
65+
)
66+
);
5667
$constructor->addArgument(new Argument('birth_date', new Object_(new Fqsen('\\' . DateTimeImmutable::class))));
5768
$constructor->addArgument(
5869
new Argument(
5970
'created_at',
6071
new Object_(new Fqsen('\\' . DateTimeImmutable::class)),
6172
new Expression(
62-
'new {{ PHPDOC6ffacd918e2f70478d2fd33dcb58c4d4 }}(\'now\')',
73+
'new {{ PHPDOCf854926c6ee2b49d3385c30295984295 }}(\'now\')',
6374
[
64-
'{{ PHPDOC6ffacd918e2f70478d2fd33dcb58c4d4 }}' => new Fqsen('\\DateTimeImmutable')
75+
'{{ PHPDOCf854926c6ee2b49d3385c30295984295 }}' => new Fqsen('\\DateTimeImmutable')
6576
]
6677
)
6778
)
@@ -73,7 +84,7 @@ public function testArgumentsAreReadCorrectly() : void
7384
new Expression(
7485
'[{{ PHPDOC19b72d1f430d952a8dfe2384dd4e93dc }}]',
7586
[
76-
'{{ PHPDOC19b72d1f430d952a8dfe2384dd4e93dc }}' => new Fqsen('\PHP8\ConstructorPromotion::DEFAULT_VALUE'),
87+
'{{ PHPDOC19b72d1f430d952a8dfe2384dd4e93dc }}' => new Fqsen('\self::DEFAULT_VALUE'),
7788
],
7889
),
7990
),
@@ -121,7 +132,7 @@ private function expectedConstructorMethod(): Method
121132
false,
122133
false,
123134
new Location(18, 264),
124-
new Location(31, 704)
135+
new Location(31, 718)
125136
);
126137
}
127138

@@ -153,9 +164,9 @@ private function expectedEmailProperty(): Property
153164
new Visibility(Visibility::PROTECTED_),
154165
null,
155166
new Expression(
156-
'new {{PHPDOCce8ae9da5b7cd6c3df2929543a9af92d}}()',
167+
'new {{ PHPDOCc27b34d4d91bc4d52190708db8447e09 }}()',
157168
[
158-
'{{ PHPDOCce8ae9da5b7cd6c3df2929543a9af92d }}' => new Fqsen('\\PHP8\\Email'),
169+
'{{ PHPDOCc27b34d4d91bc4d52190708db8447e09 }}' => new Fqsen('\\PHP8\\Email'),
159170
],
160171
),
161172
false,
@@ -186,9 +197,9 @@ private function expectedCreatedAtProperty(): Property
186197
new Visibility(Visibility::PRIVATE_),
187198
null,
188199
new Expression(
189-
'new {{ PHPDOC6ffacd918e2f70478d2fd33dcb58c4d4 }}(\'now\')',
200+
'new {{ PHPDOCf854926c6ee2b49d3385c30295984295 }}(\'now\')',
190201
[
191-
'{{ PHPDOC6ffacd918e2f70478d2fd33dcb58c4d4 }}' => new Fqsen('\\DateTimeImmutable'),
202+
'{{ PHPDOCf854926c6ee2b49d3385c30295984295 }}' => new Fqsen('\\DateTimeImmutable'),
192203
],
193204
),
194205
false,
@@ -207,7 +218,7 @@ private function expectedUsesConstantsProperty()
207218
new Expression(
208219
'[{{ PHPDOC19b72d1f430d952a8dfe2384dd4e93dc }}]',
209220
[
210-
'{{ PHPDOC19b72d1f430d952a8dfe2384dd4e93dc }}' => new Fqsen('\PHP8\ConstructorPromotion::DEFAULT_VALUE'),
221+
'{{ PHPDOC19b72d1f430d952a8dfe2384dd4e93dc }}' => new Fqsen('\self::DEFAULT_VALUE'),
211222
],
212223
),
213224
false,

tests/unit/phpDocumentor/Reflection/Php/EnumCaseTest.php

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ public function testGettingDocBlock(): void
8181
$this->assertSame($this->docBlock, $fixture->getDocBlock());
8282
}
8383

84-
/** @covers ::getValue */
8584
public function testValueCanBeOmitted(): void
8685
{
8786
$fixture = new EnumCase(
@@ -92,11 +91,6 @@ public function testValueCanBeOmitted(): void
9291
$this->assertNull($fixture->getValue());
9392
}
9493

95-
/**
96-
* @uses Expression
97-
*
98-
* @covers ::getValue
99-
*/
10094
public function testValueCanBeProvidedAsAnExpression(): void
10195
{
10296
$expression = new Expression('Enum case expression');
@@ -111,11 +105,6 @@ public function testValueCanBeProvidedAsAnExpression(): void
111105
$this->assertSame($expression, $fixture->getValue(false));
112106
}
113107

114-
/**
115-
* @uses Expression
116-
*
117-
* @covers ::getValue
118-
*/
119108
public function testValueCanBeReturnedAsString(): void
120109
{
121110
$expression = new Expression('Enum case expression');
@@ -130,7 +119,6 @@ public function testValueCanBeReturnedAsString(): void
130119
$this->assertSame('Enum case expression', $fixture->getValue(true));
131120
}
132121

133-
/** @covers ::getLocation */
134122
public function testGetLocationReturnsProvidedValue(): void
135123
{
136124
$location = new Location(15, 10);
@@ -143,11 +131,6 @@ public function testGetLocationReturnsProvidedValue(): void
143131
self::assertSame($location, $fixture->getLocation());
144132
}
145133

146-
/**
147-
* @uses Location
148-
*
149-
* @covers ::getLocation
150-
*/
151134
public function testGetLocationReturnsUnknownByDefault(): void
152135
{
153136
$fixture = new EnumCase(
@@ -158,7 +141,6 @@ public function testGetLocationReturnsUnknownByDefault(): void
158141
self::assertEquals(new Location(-1), $fixture->getLocation());
159142
}
160143

161-
/** @covers ::getEndLocation */
162144
public function testGetEndLocationReturnsProvidedValue(): void
163145
{
164146
$location = new Location(11, 23);
@@ -172,7 +154,6 @@ public function testGetEndLocationReturnsProvidedValue(): void
172154
self::assertSame($location, $fixture->getEndLocation());
173155
}
174156

175-
/** @covers ::getEndLocation */
176157
public function testGetEndLocationReturnsUnknownByDefault(): void
177158
{
178159
$fixture = new EnumCase(

tests/unit/phpDocumentor/Reflection/Php/ExpressionTest.php

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,56 +15,45 @@
1515

1616
use InvalidArgumentException;
1717
use phpDocumentor\Reflection\Fqsen;
18+
use PHPUnit\Framework\Attributes\CoversClass;
1819
use PHPUnit\Framework\TestCase;
1920

2021
use function sprintf;
2122

22-
/**
23-
* @coversDefaultClass Expression
24-
* @covers ::__construct
25-
* @covers ::<private>
26-
*/
23+
#[CoversClass(Expression::class)]
2724
final class ExpressionTest extends TestCase
2825
{
2926
private const EXAMPLE_FQSEN = '\\' . self::class;
3027
private const EXAMPLE_FQSEN_PLACEHOLDER = '{{ PHPDOC0450ed2a7bac1efcf0c13b6560767954 }}';
3128

32-
/** @covers ::generatePlaceholder */
3329
public function testGeneratingPlaceholder(): void
3430
{
3531
$placeholder = Expression::generatePlaceholder(self::EXAMPLE_FQSEN);
3632

3733
self::assertSame(self::EXAMPLE_FQSEN_PLACEHOLDER, $placeholder);
3834
}
3935

40-
/** @covers ::generatePlaceholder */
4136
public function testGeneratingPlaceholderErrorsUponPassingAnEmptyName(): void
4237
{
4338
$this->expectException(InvalidArgumentException::class);
4439

4540
Expression::generatePlaceholder('');
4641
}
4742

48-
/** @covers ::__construct */
4943
public function testExpressionTemplateCannotBeEmpty(): void
5044
{
5145
$this->expectException(InvalidArgumentException::class);
5246

5347
new Expression('', []);
5448
}
5549

56-
/** @covers ::__construct */
5750
public function testPartsShouldContainFqsensOrTypes(): void
5851
{
5952
$this->expectException(InvalidArgumentException::class);
6053

6154
new Expression('This is an expression', [self::EXAMPLE_FQSEN_PLACEHOLDER => self::EXAMPLE_FQSEN]);
6255
}
6356

64-
/**
65-
* @covers ::__construct
66-
* @covers ::getExpression
67-
*/
6857
public function testGetExpressionTemplateString(): void
6958
{
7059
$expressionTemplate = sprintf('This is an %s expression', self::EXAMPLE_FQSEN_PLACEHOLDER);
@@ -76,10 +65,6 @@ public function testGetExpressionTemplateString(): void
7665
self::assertSame($expressionTemplate, $result);
7766
}
7867

79-
/**
80-
* @covers ::__construct
81-
* @covers ::getParts
82-
*/
8368
public function testGetExtractedParts(): void
8469
{
8570
$expressionTemplate = sprintf('This is an %s expression', self::EXAMPLE_FQSEN_PLACEHOLDER);
@@ -91,7 +76,6 @@ public function testGetExtractedParts(): void
9176
self::assertSame($parts, $result);
9277
}
9378

94-
/** @covers ::__toString */
9579
public function testReplacePlaceholdersWhenCastingToString(): void
9680
{
9781
$expressionTemplate = sprintf('This is an %s expression', self::EXAMPLE_FQSEN_PLACEHOLDER);
@@ -103,7 +87,6 @@ public function testReplacePlaceholdersWhenCastingToString(): void
10387
self::assertSame(sprintf('This is an %s expression', self::EXAMPLE_FQSEN), $result);
10488
}
10589

106-
/** @covers ::render */
10790
public function testRenderingExpressionWithoutOverridesIsTheSameAsWhenCastingToString(): void
10891
{
10992
$expressionTemplate = sprintf('This is an %s expression', self::EXAMPLE_FQSEN_PLACEHOLDER);
@@ -115,7 +98,6 @@ public function testRenderingExpressionWithoutOverridesIsTheSameAsWhenCastingToS
11598
self::assertSame((string) $expression, $result);
11699
}
117100

118-
/** @covers ::render */
119101
public function testOverridePartsWhenRenderingExpression(): void
120102
{
121103
$replacement = 'ExpressionTest';

0 commit comments

Comments
 (0)