Skip to content

Commit

Permalink
NodeScopeResolver: call nodeCallback for all attribute-related nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
janedbal committed May 27, 2022
1 parent 1182199 commit 68d2e81
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 42 deletions.
72 changes: 30 additions & 42 deletions src/Analyser/NodeScopeResolver.php
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
Expand Down Expand Up @@ -395,13 +396,7 @@ private function processStmtNode(
} elseif ($stmt instanceof Node\Stmt\Function_) {
$hasYield = false;
$throwPoints = [];
foreach ($stmt->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $scope, $nodeCallback, ExpressionContext::createDeep());
}
}
}
$this->processAttributeGroups($stmt->attrGroups, $scope, $nodeCallback);
[$templateTypeMap, $phpDocParameterTypes, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure] = $this->getPhpDocs($scope, $stmt);

foreach ($stmt->params as $param) {
Expand Down Expand Up @@ -456,13 +451,7 @@ private function processStmtNode(
} elseif ($stmt instanceof Node\Stmt\ClassMethod) {
$hasYield = false;
$throwPoints = [];
foreach ($stmt->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $scope, $nodeCallback, ExpressionContext::createDeep());
}
}
}
$this->processAttributeGroups($stmt->attrGroups, $scope, $nodeCallback);
[$templateTypeMap, $phpDocParameterTypes, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure] = $this->getPhpDocs($scope, $stmt);

foreach ($stmt->params as $param) {
Expand Down Expand Up @@ -633,13 +622,7 @@ private function processStmtNode(
}

$classStatementsGatherer = new ClassStatementsGatherer($classReflection, $nodeCallback);
foreach ($stmt->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $classScope, $classStatementsGatherer, ExpressionContext::createDeep());
}
}
}
$this->processAttributeGroups($stmt->attrGroups, $classScope, $classStatementsGatherer);

$this->processStmtNodes($stmt, $stmt->stmts, $classScope, $classStatementsGatherer);
$nodeCallback(new ClassPropertiesNode($stmt, $classStatementsGatherer->getProperties(), $classStatementsGatherer->getTraitProperties(), $classStatementsGatherer->getPropertyUsages(), $classStatementsGatherer->getMethodCalls()), $classScope);
Expand All @@ -649,13 +632,8 @@ private function processStmtNode(
} elseif ($stmt instanceof Node\Stmt\Property) {
$hasYield = false;
$throwPoints = [];
foreach ($stmt->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $scope, $nodeCallback, ExpressionContext::createDeep());
}
}
}
$this->processAttributeGroups($stmt->attrGroups, $scope, $nodeCallback);

foreach ($stmt->props as $prop) {
$this->processStmtNode($prop, $scope, $nodeCallback);
[,,,,,,,,,$isReadOnly, $docComment] = $this->getPhpDocs($scope, $stmt);
Expand Down Expand Up @@ -1406,13 +1384,7 @@ private function processStmtNode(
$hasYield = false;
$throwPoints = [];
if ($stmt instanceof Node\Stmt\ClassConst) {
foreach ($stmt->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $scope, $nodeCallback, ExpressionContext::createDeep());
}
}
}
$this->processAttributeGroups($stmt->attrGroups, $scope, $nodeCallback);
}
foreach ($stmt->consts as $const) {
$nodeCallback($const, $scope);
Expand Down Expand Up @@ -3108,13 +3080,7 @@ private function processParamNode(
callable $nodeCallback,
): void
{
foreach ($param->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $scope, $nodeCallback, ExpressionContext::createDeep());
}
}
}
$this->processAttributeGroups($param->attrGroups, $scope, $nodeCallback);
$nodeCallback($param, $scope);
if ($param->type !== null) {
$nodeCallback($param->type, $scope);
Expand All @@ -3126,6 +3092,28 @@ private function processParamNode(
$this->processExprNode($param->default, $scope, $nodeCallback, ExpressionContext::createDeep());
}

/**
* @param AttributeGroup[] $attrGroups
* @param callable(Node $node, Scope $scope): void $nodeCallback
*/
private function processAttributeGroups(
array $attrGroups,
MutatingScope $scope,
callable $nodeCallback,
): void
{
foreach ($attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
foreach ($attr->args as $arg) {
$this->processExprNode($arg->value, $scope, $nodeCallback, ExpressionContext::createDeep());
$nodeCallback($arg, $scope);
}
$nodeCallback($attr, $scope);
}
$nodeCallback($attrGroup, $scope);
}
}

/**
* @param MethodReflection|FunctionReflection|null $calleeReflection
* @param Node\Arg[] $args
Expand Down
31 changes: 31 additions & 0 deletions tests/PHPStan/Node/AttributeArgRule.php
@@ -0,0 +1,31 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;

/**
* @implements Rule<Node\Arg>
*/
class AttributeArgRule implements Rule
{

public const ERROR_MESSAGE = 'Found Arg';

public function getNodeType(): string
{
return Node\Arg::class;
}

/**
* @param Node\Arg $node
* @return string[]
*/
public function processNode(Node $node, Scope $scope): array
{
return [self::ERROR_MESSAGE];
}

}
45 changes: 45 additions & 0 deletions tests/PHPStan/Node/AttributeArgRuleTest.php
@@ -0,0 +1,45 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<Rule>
*/
class AttributeArgRuleTest extends RuleTestCase
{

/**
* @return Rule<Node\Arg>
*/
protected function getRule(): Rule
{
return new AttributeArgRule();
}

public function dataRule(): iterable
{
yield [
__DIR__ . '/data/attributes.php',
AttributeArgRule::ERROR_MESSAGE,
[8, 16, 20, 23, 26, 27, 34, 40],
];
}

/**
* @param int[] $lines
* @dataProvider dataRule
*/
public function testRule(string $file, string $expectedError, array $lines): void
{
$errors = [];
foreach ($lines as $line) {
$errors[] = [$expectedError, $line];
}
$this->analyse([$file], $errors);
}

}
31 changes: 31 additions & 0 deletions tests/PHPStan/Node/AttributeGroupRule.php
@@ -0,0 +1,31 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;

/**
* @implements Rule<Node\AttributeGroup>
*/
class AttributeGroupRule implements Rule
{

public const ERROR_MESSAGE = 'Found AttributeGroup';

public function getNodeType(): string
{
return Node\AttributeGroup::class;
}

/**
* @param Node\AttributeGroup $node
* @return string[]
*/
public function processNode(Node $node, Scope $scope): array
{
return [self::ERROR_MESSAGE];
}

}
45 changes: 45 additions & 0 deletions tests/PHPStan/Node/AttributeGroupRuleTest.php
@@ -0,0 +1,45 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<Rule>
*/
class AttributeGroupRuleTest extends RuleTestCase
{

/**
* @return Rule<Node\AttributeGroup>
*/
protected function getRule(): Rule
{
return new AttributeGroupRule();
}

public function dataRule(): iterable
{
yield [
__DIR__ . '/data/attributes.php',
AttributeGroupRule::ERROR_MESSAGE,
[8, 16, 20, 23, 26, 27, 34, 40],
];
}

/**
* @param int[] $lines
* @dataProvider dataRule
*/
public function testRule(string $file, string $expectedError, array $lines): void
{
$errors = [];
foreach ($lines as $line) {
$errors[] = [$expectedError, $line];
}
$this->analyse([$file], $errors);
}

}
31 changes: 31 additions & 0 deletions tests/PHPStan/Node/AttributeRule.php
@@ -0,0 +1,31 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;

/**
* @implements Rule<Node\Attribute>
*/
class AttributeRule implements Rule
{

public const ERROR_MESSAGE = 'Found Attribute';

public function getNodeType(): string
{
return Node\Attribute::class;
}

/**
* @param Node\Attribute $node
* @return string[]
*/
public function processNode(Node $node, Scope $scope): array
{
return [self::ERROR_MESSAGE];
}

}
45 changes: 45 additions & 0 deletions tests/PHPStan/Node/AttributeRuleTest.php
@@ -0,0 +1,45 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<Rule>
*/
class AttributeRuleTest extends RuleTestCase
{

/**
* @return Rule<Node\Attribute>
*/
protected function getRule(): Rule
{
return new AttributeRule();
}

public function dataRule(): iterable
{
yield [
__DIR__ . '/data/attributes.php',
AttributeRule::ERROR_MESSAGE,
[8, 16, 20, 23, 26, 27, 34, 40],
];
}

/**
* @param int[] $lines
* @dataProvider dataRule
*/
public function testRule(string $file, string $expectedError, array $lines): void
{
$errors = [];
foreach ($lines as $line) {
$errors[] = [$expectedError, $line];
}
$this->analyse([$file], $errors);
}

}

0 comments on commit 68d2e81

Please sign in to comment.