Skip to content

Commit edd5f67

Browse files
committed
Be more strict about type definitions on param
Throw on invalid type definitions and unexpected type definitions. Not all types resolved by phpstan's parser are valid for docblocks, they might in a more complex type system but I do not see how these types would ever apply to param tags.
1 parent f359e4f commit edd5f67

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

src/DocBlock/Tags/Factory/ParamFactory.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\Deprecations\Deprecation;
88
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
99
use phpDocumentor\Reflection\DocBlock\Tag;
10+
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
1011
use phpDocumentor\Reflection\DocBlock\Tags\Param;
1112
use phpDocumentor\Reflection\TypeResolver;
1213
use phpDocumentor\Reflection\Types\Context;
@@ -15,6 +16,7 @@
1516
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
1617
use PHPStan\PhpDocParser\Ast\PhpDoc\TypelessParamTagValueNode;
1718
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
19+
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
1820
use Webmozart\Assert\Assert;
1921

2022
use function sprintf;
@@ -59,6 +61,13 @@ public function create(PhpDocTagNode $node, Context $context): Tag
5961
]
6062
);
6163

64+
if (($tagValue->type ?? null) instanceof OffsetAccessTypeNode) {
65+
return InvalidTag::create(
66+
(string) $tagValue,
67+
'param'
68+
);
69+
}
70+
6271
return new Param(
6372
trim($tagValue->parameterName, '$'),
6473
$this->typeResolver->createType($tagValue->type ?? new IdentifierTypeNode('mixed'), $context),

src/DocBlock/Tags/TagWithType.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313

1414
namespace phpDocumentor\Reflection\DocBlock\Tags;
1515

16+
use InvalidArgumentException;
1617
use phpDocumentor\Reflection\Type;
1718

1819
use function in_array;
20+
use function sprintf;
1921
use function strlen;
2022
use function substr;
2123
use function trim;
@@ -59,6 +61,12 @@ protected static function extractTypeFromBody(string $body): array
5961
}
6062
}
6163

64+
if ($nestingLevel < 0 || $nestingLevel > 0) {
65+
throw new InvalidArgumentException(
66+
sprintf('Could not find type in %s, please check for malformed notations', $body)
67+
);
68+
}
69+
6270
$description = trim(substr($body, strlen($type)));
6371

6472
return [$type, $description];

tests/integration/InterpretingDocBlocksTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use phpDocumentor\Reflection\DocBlock\Description;
1818
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
1919
use phpDocumentor\Reflection\DocBlock\Tag;
20+
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
2021
use phpDocumentor\Reflection\DocBlock\Tags\Method;
2122
use phpDocumentor\Reflection\DocBlock\Tags\MethodParameter;
2223
use phpDocumentor\Reflection\DocBlock\Tags\Param;
@@ -218,4 +219,30 @@ public function testMethodRegression(): void
218219
$docblock->getTags()
219220
);
220221
}
222+
223+
public function testInvalidTypeParamResultsInInvalidTag(): void
224+
{
225+
$docCommment = '
226+
/**
227+
* This is an example of a summary.
228+
*
229+
* @param array\Foo> $test
230+
*/
231+
';
232+
$factory = DocBlockFactory::createInstance();
233+
$docblock = $factory->create($docCommment);
234+
235+
self::assertEquals(
236+
[
237+
InvalidTag::create(
238+
'array\Foo> $test',
239+
'param',
240+
)->withError(
241+
new \InvalidArgumentException(
242+
'Could not find type in array\Foo> $test, please check for malformed notations')
243+
),
244+
],
245+
$docblock->getTags()
246+
);
247+
}
221248
}

tests/unit/DocBlock/Tags/Factory/ParamFactoryTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
1515

1616
use phpDocumentor\Reflection\DocBlock\Description;
17+
use phpDocumentor\Reflection\DocBlock\Tag;
18+
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
1719
use phpDocumentor\Reflection\DocBlock\Tags\Param;
1820
use phpDocumentor\Reflection\Fqsen;
1921
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
@@ -33,7 +35,7 @@ final class ParamFactoryTest extends TagFactoryTestCase
3335
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory::supports
3436
* @dataProvider paramInputProvider
3537
*/
36-
public function testParamIsCreated(string $input, Param $expected): void
38+
public function testParamIsCreated(string $input, Tag $expected): void
3739
{
3840
$ast = $this->parseTag($input);
3941
$factory = new ParamFactory($this->giveTypeResolver(), $this->givenDescriptionFactory());
@@ -122,6 +124,10 @@ public function paramInputProvider(): array
122124
false
123125
),
124126
],
127+
[
128+
'@param array[\Illuminate\Notifications\Channels\Notification] $notification',
129+
InvalidTag::create('array[\Illuminate\Notifications\Channels\Notification] $notification', 'param'),
130+
],
125131
];
126132
}
127133
}

0 commit comments

Comments
 (0)