-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rule for checking a dynamic call on static methods
- Loading branch information
1 parent
e4a2045
commit 2091311
Showing
5 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Rules\StrictCalls; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Expr\MethodCall; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Rules\RuleLevelHelper; | ||
use PHPStan\Type\ErrorType; | ||
|
||
class DynamicCallOnStaticMethodsRule implements \PHPStan\Rules\Rule | ||
{ | ||
|
||
/** | ||
* @var \PHPStan\Rules\RuleLevelHelper | ||
*/ | ||
private $ruleLevelHelper; | ||
|
||
public function __construct(RuleLevelHelper $ruleLevelHelper) | ||
{ | ||
$this->ruleLevelHelper = $ruleLevelHelper; | ||
} | ||
|
||
public function getNodeType(): string | ||
{ | ||
return MethodCall::class; | ||
} | ||
|
||
/** | ||
* @param \PhpParser\Node\Expr\MethodCall $node | ||
* @param \PHPStan\Analyser\Scope $scope | ||
* @return string[] | ||
*/ | ||
public function processNode(Node $node, Scope $scope): array | ||
{ | ||
if (!is_string($node->name)) { | ||
return []; | ||
} | ||
|
||
$name = $node->name; | ||
$type = $this->ruleLevelHelper->findTypeToCheck( | ||
$scope, | ||
$node->var, | ||
'' | ||
)->getType(); | ||
|
||
if ($type instanceof ErrorType || !$type->canCallMethods() || !$type->hasMethod($name)) { | ||
return []; | ||
} | ||
|
||
$methodReflection = $type->getMethod($name, $scope); | ||
if ($methodReflection->isStatic()) { | ||
return [sprintf( | ||
'Dynamic call to static method %s::%s().', | ||
$methodReflection->getDeclaringClass()->getDisplayName(), | ||
$methodReflection->getName() | ||
)]; | ||
} | ||
|
||
return []; | ||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace PHPStan\Rules\StrictCalls; | ||
|
||
use PHPStan\Rules\Rule; | ||
use PHPStan\Rules\RuleLevelHelper; | ||
|
||
class DynamicCallOnStaticMethodsRuleTest extends \PHPStan\Testing\RuleTestCase | ||
{ | ||
|
||
/** | ||
* @var bool | ||
*/ | ||
private $checkThisOnly; | ||
|
||
protected function getRule(): Rule | ||
{ | ||
$broker = $this->createBroker(); | ||
$ruleLevelHelper = new RuleLevelHelper($broker, true, $this->checkThisOnly, true); | ||
return new DynamicCallOnStaticMethodsRule($ruleLevelHelper); | ||
} | ||
|
||
public function testRule(): void | ||
{ | ||
$this->checkThisOnly = false; | ||
$this->analyse([__DIR__ . '/data/dynamic-calls-on-static-methods.php'], [ | ||
[ | ||
'Dynamic call to static method StrictCalls\ClassWithStaticMethod::foo().', | ||
14, | ||
], | ||
[ | ||
'Dynamic call to static method StrictCalls\ClassWithStaticMethod::foo().', | ||
21, | ||
], | ||
[ | ||
'Dynamic call to static method StrictCalls\ClassUsingTrait::foo().', | ||
34, | ||
], | ||
[ | ||
'Dynamic call to static method StrictCalls\ClassUsingTrait::foo().', | ||
46, | ||
], | ||
]); | ||
} | ||
|
||
public function testRuleOnThisOnly(): void | ||
{ | ||
$this->checkThisOnly = true; | ||
$this->analyse([__DIR__ . '/data/dynamic-calls-on-static-methods.php'], [ | ||
[ | ||
'Dynamic call to static method StrictCalls\ClassWithStaticMethod::foo().', | ||
14, | ||
], | ||
[ | ||
'Dynamic call to static method StrictCalls\ClassUsingTrait::foo().', | ||
34, | ||
], | ||
]); | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
tests/Rules/StrictCalls/data/dynamic-calls-on-static-methods.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
namespace StrictCalls; | ||
|
||
class ClassWithStaticMethod | ||
{ | ||
public static function foo() | ||
{ | ||
|
||
} | ||
|
||
public function bar() | ||
{ | ||
$this->foo(); | ||
$this->bar(); | ||
} | ||
} | ||
|
||
function () { | ||
$classWithStaticMethod = new ClassWithStaticMethod(); | ||
$classWithStaticMethod->foo(); | ||
$classWithStaticMethod->bar(); | ||
}; | ||
|
||
trait TraitWithStaticMethod | ||
{ | ||
public static function foo() | ||
{ | ||
|
||
} | ||
|
||
public function bar() | ||
{ | ||
$this->foo(); | ||
$this->bar(); | ||
} | ||
} | ||
|
||
class ClassUsingTrait | ||
{ | ||
use TraitWithStaticMethod; | ||
} | ||
|
||
function () { | ||
$classUsingTrait = new ClassUsingTrait(); | ||
$classUsingTrait->foo(); | ||
$classUsingTrait->bar(); | ||
}; |
2091311
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lookyman @ondrejmirtes:
What is the best way with PHPUnit and well-known Dynamic call to static method PHPUnit\Framework\Assert::assert*()?
Should I manually add item to
ignoreErrors
in every project withphpstan/phpstan-strict-rules
?Thank you.
2091311
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2091311
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And what about suppress these errors in
phpstan/phpstan-phpunit
?2091311
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a good idea. I.e. I use phpstan-phpunit and I don't want dynamic calls to static methods. :)
2091311
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.