Skip to content

Commit fc5515a

Browse files
committed
Handle invalid type aliases better
1 parent 31b6296 commit fc5515a

File tree

7 files changed

+77
-2
lines changed

7 files changed

+77
-2
lines changed

src/PhpDoc/TypeNodeResolver.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
2929
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
3030
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
31+
use PHPStan\PhpDocParser\Ast\Type\InvalidTypeNode;
3132
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
3233
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
3334
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
@@ -164,6 +165,8 @@ public function resolve(TypeNode $typeNode, NameScope $nameScope): Type
164165
return $this->resolveConstTypeNode($typeNode, $nameScope);
165166
} elseif ($typeNode instanceof OffsetAccessTypeNode) {
166167
return $this->resolveOffsetAccessNode($typeNode, $nameScope);
168+
} elseif ($typeNode instanceof InvalidTypeNode) {
169+
return new MixedType(true);
167170
}
168171

169172
return new ErrorType();

src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Node\VirtualNode;
88
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
9+
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasTagValueNode;
10+
use PHPStan\PhpDocParser\Ast\Type\InvalidTypeNode;
911
use PHPStan\PhpDocParser\Lexer\Lexer;
1012
use PHPStan\PhpDocParser\Parser\PhpDocParser;
1113
use PHPStan\PhpDocParser\Parser\TokenIterator;
@@ -71,11 +73,24 @@ public function processNode(Node $node, Scope $scope): array
7173

7274
$errors = [];
7375
foreach ($phpDocNode->getTags() as $phpDocTag) {
74-
if (!($phpDocTag->value instanceof InvalidTagValueNode)) {
76+
if (strpos($phpDocTag->name, '@psalm-') === 0) {
7577
continue;
7678
}
7779

78-
if (strpos($phpDocTag->name, '@psalm-') === 0) {
80+
if ($phpDocTag->value instanceof TypeAliasTagValueNode) {
81+
if (!$phpDocTag->value->type instanceof InvalidTypeNode) {
82+
continue;
83+
}
84+
85+
$errors[] = RuleErrorBuilder::message(sprintf(
86+
'PHPDoc tag %s %s has invalid value: %s',
87+
$phpDocTag->name,
88+
$phpDocTag->value->alias,
89+
$phpDocTag->value->type->getException()->getMessage(),
90+
))->build();
91+
92+
continue;
93+
} elseif (!($phpDocTag->value instanceof InvalidTagValueNode)) {
7994
continue;
8095
}
8196

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,7 @@ public function dataFileAsserts(): iterable
12211221
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/PhpDoc/data/bug-8609-function.php');
12221222
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9131.php');
12231223
yield from $this->gatherAssertTypes(__DIR__ . '/data/more-types.php');
1224+
yield from $this->gatherAssertTypes(__DIR__ . '/data/invalid-type-aliases.php');
12241225
}
12251226

12261227
/**
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace InvalidTypeAliases;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/** @psalm-type MyObject = what{foo: 'bar'} */
8+
class HelloWorld
9+
{
10+
/** @psalm-param MyObject $a */
11+
public function acceptsAlias($a)
12+
{
13+
assertType('mixed', $a);
14+
assertType('mixed', $this->returnsAlias());
15+
}
16+
17+
/** @psalm-return MyObject */
18+
public function returnsAlias()
19+
{
20+
21+
}
22+
}

tests/PHPStan/Rules/Classes/data/local-type-aliases.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,9 @@ class Generic
6262
class Invalid
6363
{
6464
}
65+
66+
/** @psalm-type MyObject = what{} */
67+
class InvalidTypeDefinitionToIgnoreBecauseItsAParseErrorAlreadyReportedInInvalidPhpDocTagValueRule
68+
{
69+
70+
}

tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,15 @@ public function testBug4731WithoutFirstTag(): void
129129
$this->analyse([__DIR__ . '/data/bug-4731-no-first-tag.php'], []);
130130
}
131131

132+
public function testInvalidTypeInTypeAlias(): void
133+
{
134+
$this->checkAllInvalidPhpDocs = true;
135+
$this->analyse([__DIR__ . '/data/invalid-type-type-alias.php'], [
136+
[
137+
'PHPDoc tag @phpstan-type InvalidFoo has invalid value: Unexpected token "{", expected TOKEN_PHPDOC_EOL at offset 65',
138+
12,
139+
],
140+
]);
141+
}
142+
132143
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace InvalidTypeInTypeAlias;
4+
5+
/**
6+
* @phpstan-type Foo array{}
7+
* @phpstan-type InvalidFoo what{}
8+
*
9+
* @psalm-type Foo array{}
10+
* @psalm-type InvalidFoo what{}
11+
*/
12+
class Foo
13+
{
14+
15+
16+
17+
}

0 commit comments

Comments
 (0)