Skip to content

Commit 56bfb92

Browse files
committed
[BE] Validate @var tags
1 parent 4e30a47 commit 56bfb92

File tree

7 files changed

+51
-70
lines changed

7 files changed

+51
-70
lines changed

changelog-2.0.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ Major new features 🚀
77

88
* **Array `list` type** ([#1751](https://github.com/phpstan/phpstan-src/pull/1751)), #3311, #8185, #6243, thanks @rvanvelzen!
99
* Lists are arrays with sequential integer keys starting at 0
10-
* Lower memory consumption thanks to breaking up of reference cycles
10+
* **Validate inline PHPDoc `@var` tag** type against native type (level 2) (https://github.com/phpstan/phpstan-src/commit/a69e3bc2f1e87f6da1e65d7935f1cc36bd5c42fe)
11+
* Set [`reportWrongPhpDocTypeInVarTag`](https://phpstan.org/config-reference#reportwrongphpdoctypeinvartag) to `true` to have all types validated, not just native ones
12+
* **Lower memory consumption** thanks to breaking up of reference cycles
1113
* [Learn more »](https://phpstan.org/blog/preprocessing-ast-for-custom-rules)
1214
* In testing the memory consumption was reduced by 50–70 %.
13-
* **Enhancements in Handling Parameters Passed by Reference**
15+
* **Enhancements in handling parameters passed by reference**
1416
* [Learn more on phpstan.org](https://phpstan.org/blog/enhancements-in-handling-parameters-passed-by-reference)
1517
* [#2941](https://github.com/phpstan/phpstan-src/pull/2941), thanks @ljmaskey!
1618
* LogicalXorConstantConditionRule (level 4) (https://github.com/phpstan/phpstan-src/commit/3a12724fd636b1bcf36c22b36e8f765d97150895, https://github.com/phpstan/phpstan-src/commit/3b011f6524254dad0f16840fdcfdbe7421548617), #7539
@@ -56,8 +58,6 @@ Bleeding edge (TODO move to other sections)
5658
* Move IllegalConstructorMethodCallRule and IllegalConstructorStaticCallRule to phpstan-strict-rules (https://github.com/phpstan/phpstan-src/commit/124b30f98c182193187be0b9c2e151e477429b7a, https://github.com/phpstan/phpstan-strict-rules/commit/0c82c96f2a55d8b91bbc7ee6512c94f68a206b43)
5759
* Add `@readonly` rule that disallows default values ([#1391](https://github.com/phpstan/phpstan-src/pull/1391)), thanks @herndlm!
5860
* MissingMagicSerializationMethodsRule ([#1711](https://github.com/phpstan/phpstan-src/pull/1711)), #7482, thanks @staabm!
59-
* Validate inline PHPDoc `@var` tag type against native type (https://github.com/phpstan/phpstan-src/commit/a69e3bc2f1e87f6da1e65d7935f1cc36bd5c42fe)
60-
* Set [`reportWrongPhpDocTypeInVarTag`](https://phpstan.org/config-reference#reportwrongphpdoctypeinvartag) to `true` to have all types validated, not just native ones
6161
* Always report always true conditions, except for last elseif and match arm ([#2105](https://github.com/phpstan/phpstan-src/pull/2105)), thanks @staabm!
6262
* Disable "unreachable branches" rules: UnreachableIfBranchesRule, UnreachableTernaryElseBranchRule, unreachable arm error in MatchExpressionRule
6363
* Because "always true" is always reported, these are no longer needed

conf/bleedingEdge.neon

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ parameters:
1515
alwaysCheckTooWideReturnTypeFinalMethods: true
1616
alwaysTrueAlwaysReported: true
1717
disableUnreachableBranchesRules: true
18-
varTagType: true
1918
closureDefaultParameterTypeRule: true
2019
propertyVariance: true
2120
magicConstantOutOfContext: true

conf/config.level2.neon

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ rules:
5252
- PHPStan\Rules\PhpDoc\IncompatiblePropertyPhpDocTypeRule
5353
- PHPStan\Rules\PhpDoc\InvalidThrowsPhpDocValueRule
5454
- PHPStan\Rules\PhpDoc\IncompatibleParamImmediatelyInvokedCallableRule
55+
- PHPStan\Rules\PhpDoc\VarTagChangedExpressionTypeRule
56+
- PHPStan\Rules\PhpDoc\WrongVariableNameInVarTagRule
5557
- PHPStan\Rules\Properties\AccessPrivatePropertyThroughStaticRule
5658
- PHPStan\Rules\Classes\RequireImplementsRule
5759
- PHPStan\Rules\Classes\RequireExtendsRule
@@ -68,8 +70,6 @@ conditionalTags:
6870
phpstan.rules.rule: %featureToggles.illegalConstructorMethodCall%
6971
PHPStan\Rules\Methods\IllegalConstructorStaticCallRule:
7072
phpstan.rules.rule: %featureToggles.illegalConstructorMethodCall%
71-
PHPStan\Rules\PhpDoc\VarTagChangedExpressionTypeRule:
72-
phpstan.rules.rule: %featureToggles.varTagType%
7373
PHPStan\Rules\Generics\PropertyVarianceRule:
7474
phpstan.rules.rule: %featureToggles.propertyVariance%
7575
PHPStan\Rules\Pure\PureFunctionRule:
@@ -125,14 +125,6 @@ services:
125125
class: PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule
126126
tags:
127127
- phpstan.rules.rule
128-
-
129-
class: PHPStan\Rules\PhpDoc\VarTagChangedExpressionTypeRule
130-
-
131-
class: PHPStan\Rules\PhpDoc\WrongVariableNameInVarTagRule
132-
arguments:
133-
checkTypeAgainstNativeType: %featureToggles.varTagType%
134-
tags:
135-
- phpstan.rules.rule
136128
-
137129
class: PHPStan\Rules\Generics\PropertyVarianceRule
138130
arguments:

conf/config.neon

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ parameters:
3636
alwaysCheckTooWideReturnTypeFinalMethods: false
3737
alwaysTrueAlwaysReported: false
3838
disableUnreachableBranchesRules: false
39-
varTagType: false
4039
closureDefaultParameterTypeRule: false
4140
propertyVariance: false
4241
stricterFunctionMap: false

conf/parametersSchema.neon

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ parametersSchema:
4242
alwaysCheckTooWideReturnTypeFinalMethods: bool()
4343
alwaysTrueAlwaysReported: bool()
4444
disableUnreachableBranchesRules: bool()
45-
varTagType: bool()
4645
closureDefaultParameterTypeRule: bool()
4746
propertyVariance: bool()
4847
stricterFunctionMap: bool()

src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ final class WrongVariableNameInVarTagRule implements Rule
3737
public function __construct(
3838
private FileTypeMapper $fileTypeMapper,
3939
private VarTagTypeRuleHelper $varTagTypeRuleHelper,
40-
private bool $checkTypeAgainstNativeType,
4140
)
4241
{
4342
}
@@ -138,11 +137,6 @@ private function processAssign(Scope $scope, Node\Expr $var, Node\Expr $expr, ar
138137
$errors = [];
139138
$hasMultipleMessage = false;
140139
$assignedVariables = $this->getAssignedVariables($var);
141-
if ($this->checkTypeAgainstNativeType) {
142-
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var, $expr, $varTags, $assignedVariables) as $error) {
143-
$errors[] = $error;
144-
}
145-
}
146140
foreach (array_keys($varTags) as $key) {
147141
if (is_int($key)) {
148142
if (count($varTags) !== 1) {
@@ -181,6 +175,12 @@ private function processAssign(Scope $scope, Node\Expr $var, Node\Expr $expr, ar
181175
}
182176
}
183177

178+
if (count($errors) === 0) {
179+
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var, $expr, $varTags, $assignedVariables) as $error) {
180+
$errors[] = $error;
181+
}
182+
}
183+
184184
return $errors;
185185
}
186186

@@ -251,19 +251,17 @@ private function processForeach(Scope $scope, Node\Expr $iterateeExpr, ?Node\Exp
251251
))->identifier('varTag.differentVariable')->build();
252252
}
253253

254-
if ($this->checkTypeAgainstNativeType) {
255-
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $iterateeExpr, $iterateeExpr, $varTags, $variableNames) as $error) {
256-
$errors[] = $error;
257-
}
258-
if ($keyVar !== null) {
259-
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $keyVar, new GetIterableKeyTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) {
260-
$errors[] = $error;
261-
}
262-
}
263-
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $valueVar, new GetIterableValueTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) {
254+
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $iterateeExpr, $iterateeExpr, $varTags, $variableNames) as $error) {
255+
$errors[] = $error;
256+
}
257+
if ($keyVar !== null) {
258+
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $keyVar, new GetIterableKeyTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) {
264259
$errors[] = $error;
265260
}
266261
}
262+
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $valueVar, new GetIterableValueTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) {
263+
$errors[] = $error;
264+
}
267265

268266
return $errors;
269267
}
@@ -321,14 +319,12 @@ private function processStatic(Scope $scope, array $vars, array $varTags): array
321319
))->identifier('varTag.differentVariable')->build();
322320
}
323321

324-
if ($this->checkTypeAgainstNativeType) {
325-
foreach ($vars as $var) {
326-
if ($var->default === null) {
327-
continue;
328-
}
329-
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var->var, $var->default, $varTags, $variableNames) as $error) {
330-
$errors[] = $error;
331-
}
322+
foreach ($vars as $var) {
323+
if ($var->default === null) {
324+
continue;
325+
}
326+
foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var->var, $var->default, $varTags, $variableNames) as $error) {
327+
$errors[] = $error;
332328
}
333329
}
334330

tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
class WrongVariableNameInVarTagRuleTest extends RuleTestCase
1414
{
1515

16-
private bool $checkTypeAgainstNativeType = false;
17-
1816
private bool $checkTypeAgainstPhpDocType = false;
1917

2018
private bool $strictWideningCheck = false;
@@ -24,13 +22,20 @@ protected function getRule(): Rule
2422
return new WrongVariableNameInVarTagRule(
2523
self::getContainer()->getByType(FileTypeMapper::class),
2624
new VarTagTypeRuleHelper($this->checkTypeAgainstPhpDocType, $this->strictWideningCheck),
27-
$this->checkTypeAgainstNativeType,
2825
);
2926
}
3027

3128
public function testRule(): void
3229
{
3330
$this->analyse([__DIR__ . '/data/wrong-variable-name-var.php'], [
31+
[
32+
'PHPDoc tag @var with type int is not subtype of native type void.',
33+
11,
34+
],
35+
[
36+
'PHPDoc tag @var with type int is not subtype of native type void.',
37+
14,
38+
],
3439
[
3540
'Variable $foo in PHPDoc tag @var does not match assigned variable $test.',
3641
17,
@@ -71,6 +76,10 @@ public function testRule(): void
7176
'Variable $foo in PHPDoc tag @var does not exist.',
7277
109,
7378
],
79+
[
80+
'PHPDoc tag @var with type int is not subtype of native type void.',
81+
120,
82+
],
7483
[
7584
'Multiple PHPDoc @var tags above single variable assignment are not supported.',
7685
126,
@@ -253,12 +262,9 @@ public function dataReportWrongType(): iterable
253262
],
254263
];
255264

256-
yield [false, false, false, []];
257-
yield [true, false, false, $nativeCheckOnly];
258-
yield [true, false, true, $nativeCheckOnly];
259-
yield [false, true, false, []];
260-
yield [false, true, true, []];
261-
yield [true, true, false, [
265+
yield [false, false, $nativeCheckOnly];
266+
yield [false, true, $nativeCheckOnly];
267+
yield [true, false, [
262268
[
263269
'PHPDoc tag @var with type string|null is not subtype of native type string.',
264270
14,
@@ -349,7 +355,7 @@ public function dataReportWrongType(): iterable
349355
204,
350356
],
351357
]];
352-
yield [true, true, true, [
358+
yield [true, true, [
353359
[
354360
'PHPDoc tag @var with type string|null is not subtype of native type string.',
355361
14,
@@ -469,43 +475,33 @@ public function dataReportWrongType(): iterable
469475
/**
470476
* @dataProvider dataPermutateCheckTypeAgainst
471477
*/
472-
public function testEmptyArrayInitWithWiderPhpDoc(bool $checkTypeAgainstNativeType, bool $checkTypeAgainstPhpDocType): void
478+
public function testEmptyArrayInitWithWiderPhpDoc(bool $checkTypeAgainstPhpDocType): void
473479
{
474-
$this->checkTypeAgainstNativeType = $checkTypeAgainstNativeType;
475480
$this->checkTypeAgainstPhpDocType = $checkTypeAgainstPhpDocType;
476-
477-
$errors = !$checkTypeAgainstNativeType
478-
? []
479-
: [
480-
[
481-
'PHPDoc tag @var with type int is not subtype of native type array{}.',
482-
24,
483-
],
484-
];
485-
486-
$this->analyse([__DIR__ . '/data/var-above-empty-array-widening.php'], $errors);
481+
$this->analyse([__DIR__ . '/data/var-above-empty-array-widening.php'], [
482+
[
483+
'PHPDoc tag @var with type int is not subtype of native type array{}.',
484+
24,
485+
],
486+
]);
487487
}
488488

489489
public function dataPermutateCheckTypeAgainst(): iterable
490490
{
491-
yield [true, true];
492-
yield [false, true];
493-
yield [true, false];
494-
yield [false, false];
491+
yield [true];
492+
yield [false];
495493
}
496494

497495
/**
498496
* @dataProvider dataReportWrongType
499497
* @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
500498
*/
501499
public function testReportWrongType(
502-
bool $checkTypeAgainstNativeType,
503500
bool $checkTypeAgainstPhpDocType,
504501
bool $strictWideningCheck,
505502
array $expectedErrors,
506503
): void
507504
{
508-
$this->checkTypeAgainstNativeType = $checkTypeAgainstNativeType;
509505
$this->checkTypeAgainstPhpDocType = $checkTypeAgainstPhpDocType;
510506
$this->strictWideningCheck = $strictWideningCheck;
511507
$this->analyse([__DIR__ . '/data/wrong-var-native-type.php'], $expectedErrors);

0 commit comments

Comments
 (0)