Skip to content

Commit

Permalink
Bleeding edge - detect wrong usage of @var PHPDoc tag
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Feb 10, 2021
1 parent 4f7ac53 commit 5886053
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 6 deletions.
1 change: 1 addition & 0 deletions conf/bleedingEdge.neon
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ parameters:
checkLogicalAndConstantCondition: true
checkLogicalOrConstantCondition: true
checkMissingTemplateTypeInParameter: true
wrongVarUsage: true
7 changes: 6 additions & 1 deletion conf/config.level2.neon
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ rules:
- PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule
- PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule
- PHPStan\Rules\PhpDoc\InvalidThrowsPhpDocValueRule
- PHPStan\Rules\PhpDoc\WrongVariableNameInVarTagRule

services:
-
Expand All @@ -52,3 +51,9 @@ services:
checkMissingVarTagTypehint: %checkMissingVarTagTypehint%
tags:
- phpstan.rules.rule
-
class: PHPStan\Rules\PhpDoc\WrongVariableNameInVarTagRule
arguments:
checkWrongVarUsage: %featureToggles.wrongVarUsage%
tags:
- phpstan.rules.rule
4 changes: 3 additions & 1 deletion conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ parameters:
checkLogicalAndConstantCondition: false
checkLogicalOrConstantCondition: false
checkMissingTemplateTypeInParameter: false
wrongVarUsage: false
fileExtensions:
- php
checkAlwaysTrueCheckTypeFunctionCall: false
Expand Down Expand Up @@ -176,7 +177,8 @@ parametersSchema:
detectDuplicateStubFiles: bool(),
checkLogicalAndConstantCondition: bool(),
checkLogicalOrConstantCondition: bool(),
checkMissingTemplateTypeInParameter: bool()
checkMissingTemplateTypeInParameter: bool(),
wrongVarUsage: bool()
])
fileExtensions: listOf(string())
checkAlwaysTrueCheckTypeFunctionCall: bool()
Expand Down
39 changes: 36 additions & 3 deletions src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
use PHPStan\Analyser\Scope;
use PHPStan\Node\UnreachableStatementNode;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Node\InClassNode;
use PHPStan\Node\InFunctionNode;
use PHPStan\Node\VirtualNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\FileTypeMapper;
Expand All @@ -19,9 +22,15 @@ class WrongVariableNameInVarTagRule implements Rule

private FileTypeMapper $fileTypeMapper;

public function __construct(FileTypeMapper $fileTypeMapper)
private bool $checkWrongVarUsage;

public function __construct(
FileTypeMapper $fileTypeMapper,
bool $checkWrongVarUsage = false
)
{
$this->fileTypeMapper = $fileTypeMapper;
$this->checkWrongVarUsage = $checkWrongVarUsage;
}

public function getNodeType(): string
Expand All @@ -36,7 +45,7 @@ public function processNode(Node $node, Scope $scope): array
|| $node instanceof Node\Stmt\PropertyProperty
|| $node instanceof Node\Stmt\ClassConst
|| $node instanceof Node\Stmt\Const_
|| $node instanceof UnreachableStatementNode
|| ($node instanceof VirtualNode && !$node instanceof InFunctionNode && !$node instanceof InClassMethodNode && !$node instanceof InClassNode)
) {
return [];
}
Expand Down Expand Up @@ -83,6 +92,30 @@ public function processNode(Node $node, Scope $scope): array
return $this->processGlobal($scope, $node, $varTags);
}

if ($node instanceof InClassNode || $node instanceof InClassMethodNode || $node instanceof InFunctionNode) {
if ($this->checkWrongVarUsage) {
$description = 'a function';
$originalNode = $node->getOriginalNode();
if ($originalNode instanceof Node\Stmt\Interface_) {
$description = 'an interface';
} elseif ($originalNode instanceof Node\Stmt\Class_) {
$description = 'a class';
} elseif ($originalNode instanceof Node\Stmt\Trait_) {
throw new \PHPStan\ShouldNotHappenException();
} elseif ($originalNode instanceof Node\Stmt\ClassMethod) {
$description = 'a method';
}
return [
RuleErrorBuilder::message(sprintf(
'PHPDoc tag @var above %s has no effect.',
$description
))->build(),
];
}

return [];
}

return $this->processStmt($scope, $varTags, null);
}

Expand Down
15 changes: 14 additions & 1 deletion tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class WrongVariableNameInVarTagRuleTest extends RuleTestCase
protected function getRule(): Rule
{
return new WrongVariableNameInVarTagRule(
self::getContainer()->getByType(FileTypeMapper::class)
self::getContainer()->getByType(FileTypeMapper::class),
true
);
}

Expand Down Expand Up @@ -110,6 +111,18 @@ public function testRule(): void
'Variable $slots in PHPDoc tag @var does not match assigned variable $itemSlots.',
280,
],
[
'PHPDoc tag @var above a class has no effect.',
300,
],
[
'PHPDoc tag @var above a method has no effect.',
304,
],
[
'PHPDoc tag @var above a function has no effect.',
312,
],
]);
}

Expand Down
20 changes: 20 additions & 0 deletions tests/PHPStan/Rules/PhpDoc/data/wrong-variable-name-var.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,23 @@ public function doSit(): void
}

}

/**
* @var string
*/
class VarInWrongPlaces
{

/** @var int $a */
public function doFoo($a)
{

}

}

/** @var int */
function doFoo(): void
{

}

0 comments on commit 5886053

Please sign in to comment.