Skip to content

Commit a04e0be

Browse files
committed
InvalidPhpDocTagValueRule - backward compatibility of the error message without bleedingEdge
1 parent 74d1c9a commit a04e0be

9 files changed

+167
-4
lines changed

conf/bleedingEdge.neon

+1
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ parameters:
3737
propertyVariance: true
3838
genericPrototypeMessage: true
3939
stricterFunctionMap: true
40+
invalidPhpDocTagLine: true

conf/config.level2.neon

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ services:
8181
class: PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule
8282
arguments:
8383
checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs%
84+
invalidPhpDocTagLine: %featureToggles.invalidPhpDocTagLine%
8485
tags:
8586
- phpstan.rules.rule
8687
-

conf/config.neon

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ parameters:
6767
propertyVariance: false
6868
genericPrototypeMessage: false
6969
stricterFunctionMap: false
70+
invalidPhpDocTagLine: false
7071
fileExtensions:
7172
- php
7273
checkAdvancedIsset: false
@@ -304,6 +305,7 @@ parametersSchema:
304305
propertyVariance: bool()
305306
genericPrototypeMessage: bool()
306307
stricterFunctionMap: bool()
308+
invalidPhpDocTagLine: bool()
307309
])
308310
fileExtensions: listOf(string())
309311
checkAdvancedIsset: bool()

src/PhpDoc/StubValidator.php

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
180180
$container->getByType(Lexer::class),
181181
$container->getByType(PhpDocParser::class),
182182
$container->getParameter('featureToggles')['allInvalidPhpDocs'],
183+
$container->getParameter('featureToggles')['invalidPhpDocTagLine'],
183184
),
184185
new InvalidThrowsPhpDocValueRule($fileTypeMapper),
185186

src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\PhpDoc;
44

5+
use Nette\Utils\Strings;
56
use PhpParser\Node;
67
use PHPStan\Analyser\Scope;
78
use PHPStan\Node\VirtualNode;
@@ -26,6 +27,7 @@ public function __construct(
2627
private Lexer $phpDocLexer,
2728
private PhpDocParser $phpDocParser,
2829
private bool $checkAllInvalidPhpDocs,
30+
private bool $invalidPhpDocTagLine,
2931
)
3032
{
3133
}
@@ -86,7 +88,7 @@ public function processNode(Node $node, Scope $scope): array
8688
'PHPDoc tag %s %s has invalid value: %s',
8789
$phpDocTag->name,
8890
$phpDocTag->value->alias,
89-
$phpDocTag->value->type->getException()->getMessage(),
91+
$this->trimExceptionMessage($phpDocTag->value->type->getException()->getMessage()),
9092
))->build();
9193

9294
continue;
@@ -98,11 +100,20 @@ public function processNode(Node $node, Scope $scope): array
98100
'PHPDoc tag %s has invalid value (%s): %s',
99101
$phpDocTag->name,
100102
$phpDocTag->value->value,
101-
$phpDocTag->value->exception->getMessage(),
103+
$this->trimExceptionMessage($phpDocTag->value->exception->getMessage()),
102104
))->build();
103105
}
104106

105107
return $errors;
106108
}
107109

110+
private function trimExceptionMessage(string $message): string
111+
{
112+
if ($this->invalidPhpDocTagLine) {
113+
return $message;
114+
}
115+
116+
return Strings::replace($message, '~( on line \d+)$~', '');
117+
}
118+
108119
}

tests/PHPStan/Command/ErrorFormatter/data/unixBaseline.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ parameters:
1111
path: WindowsNewlines.php
1212

1313
-
14-
message: "#^PHPDoc tag @param has invalid value \\(\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected type at offset 113 on line 4$#"
14+
message: "#^PHPDoc tag @param has invalid value \\(\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected type at offset 113$#"
1515
count: 1
1616
path: WindowsNewlines.php
1717

tests/PHPStan/Command/ErrorFormatter/data/windowsBaseline.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ parameters:
1111
path: UnixNewlines.php
1212

1313
-
14-
message: "#^PHPDoc tag @param has invalid value \\(\\)\\: Unexpected token \"\\\\r\\\\n\\\\t \\* \", expected type at offset 110 on line 4$#"
14+
message: "#^PHPDoc tag @param has invalid value \\(\\)\\: Unexpected token \"\\\\r\\\\n\\\\t \\* \", expected type at offset 110$#"
1515
count: 1
1616
path: UnixNewlines.php
1717

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\PhpDoc;
4+
5+
use PHPStan\PhpDocParser\Lexer\Lexer;
6+
use PHPStan\PhpDocParser\Parser\PhpDocParser;
7+
use PHPStan\Rules\Rule;
8+
use PHPStan\Testing\RuleTestCase;
9+
use function array_merge;
10+
11+
/**
12+
* @extends RuleTestCase<InvalidPhpDocTagValueRule>
13+
*/
14+
class InvalidPhpDocTagValueRuleNoBleedingEdgeTest extends RuleTestCase
15+
{
16+
17+
private bool $checkAllInvalidPhpDocs;
18+
19+
protected function getRule(): Rule
20+
{
21+
return new InvalidPhpDocTagValueRule(
22+
self::getContainer()->getByType(Lexer::class),
23+
self::getContainer()->getByType(PhpDocParser::class),
24+
$this->checkAllInvalidPhpDocs,
25+
false,
26+
);
27+
}
28+
29+
public function dataRule(): iterable
30+
{
31+
$errors = [
32+
[
33+
'PHPDoc tag @param has invalid value (): Unexpected token "\n * ", expected type at offset 13',
34+
25,
35+
],
36+
[
37+
'PHPDoc tag @param has invalid value (A & B | C $paramNameA): Unexpected token "|", expected variable at offset 72',
38+
25,
39+
],
40+
[
41+
'PHPDoc tag @param has invalid value ((A & B $paramNameB): Unexpected token "$paramNameB", expected \')\' at offset 105',
42+
25,
43+
],
44+
[
45+
'PHPDoc tag @param has invalid value (~A & B $paramNameC): Unexpected token "~A", expected type at offset 127',
46+
25,
47+
],
48+
[
49+
'PHPDoc tag @var has invalid value (): Unexpected token "\n * ", expected type at offset 156',
50+
25,
51+
],
52+
[
53+
'PHPDoc tag @var has invalid value ($invalid): Unexpected token "$invalid", expected type at offset 165',
54+
25,
55+
],
56+
[
57+
'PHPDoc tag @var has invalid value ($invalid Foo): Unexpected token "$invalid", expected type at offset 182',
58+
25,
59+
],
60+
[
61+
'PHPDoc tag @return has invalid value (): Unexpected token "\n * ", expected type at offset 208',
62+
25,
63+
],
64+
[
65+
'PHPDoc tag @return has invalid value ([int, string]): Unexpected token "[", expected type at offset 220',
66+
25,
67+
],
68+
[
69+
'PHPDoc tag @return has invalid value (A & B | C): Unexpected token "|", expected TOKEN_OTHER at offset 251',
70+
25,
71+
],
72+
[
73+
'PHPDoc tag @var has invalid value (\\\Foo|\Bar $test): Unexpected token "\\\\\\\Foo|\\\Bar", expected type at offset 9',
74+
29,
75+
],
76+
[
77+
'PHPDoc tag @var has invalid value ((Foo|Bar): Unexpected token "*/", expected \')\' at offset 18',
78+
62,
79+
],
80+
[
81+
'PHPDoc tag @throws has invalid value ((\Exception): Unexpected token "*/", expected \')\' at offset 24',
82+
72,
83+
],
84+
[
85+
'PHPDoc tag @var has invalid value ((Foo|Bar): Unexpected token "*/", expected \')\' at offset 18',
86+
81,
87+
],
88+
[
89+
'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15',
90+
89,
91+
],
92+
[
93+
'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15',
94+
92,
95+
],
96+
];
97+
98+
yield [false, $errors];
99+
yield [true, array_merge($errors, [
100+
[
101+
'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15',
102+
102,
103+
],
104+
])];
105+
}
106+
107+
/**
108+
* @dataProvider dataRule
109+
* @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
110+
*/
111+
public function testRule(bool $checkAllInvalidPhpDocs, array $expectedErrors): void
112+
{
113+
$this->checkAllInvalidPhpDocs = $checkAllInvalidPhpDocs;
114+
$this->analyse([__DIR__ . '/data/invalid-phpdoc.php'], $expectedErrors);
115+
}
116+
117+
public function testBug4731(): void
118+
{
119+
$this->checkAllInvalidPhpDocs = true;
120+
$this->analyse([__DIR__ . '/data/bug-4731.php'], []);
121+
}
122+
123+
public function testBug4731WithoutFirstTag(): void
124+
{
125+
$this->checkAllInvalidPhpDocs = true;
126+
$this->analyse([__DIR__ . '/data/bug-4731-no-first-tag.php'], []);
127+
}
128+
129+
public function testInvalidTypeInTypeAlias(): void
130+
{
131+
$this->checkAllInvalidPhpDocs = true;
132+
$this->analyse([__DIR__ . '/data/invalid-type-type-alias.php'], [
133+
[
134+
'PHPDoc tag @phpstan-type InvalidFoo has invalid value: Unexpected token "{", expected TOKEN_PHPDOC_EOL at offset 65',
135+
12,
136+
],
137+
]);
138+
}
139+
140+
public static function getAdditionalConfigFiles(): array
141+
{
142+
// reset bleedingEdge
143+
return [];
144+
}
145+
146+
}

tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ protected function getRule(): Rule
2222
self::getContainer()->getByType(Lexer::class),
2323
self::getContainer()->getByType(PhpDocParser::class),
2424
$this->checkAllInvalidPhpDocs,
25+
true,
2526
);
2627
}
2728

0 commit comments

Comments
 (0)