Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trust static method call #55

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions src/Rules/Exceptions/MustRethrowRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
use Exception;
use function in_array;
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\Node\Stmt\Catch_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\Broker;
use PHPStan\Rules\Rule;
Expand Down Expand Up @@ -49,15 +52,34 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$exceptionVarName = $node->var->name;

// Let's visit and find a throw.
$visitor = new class() extends NodeVisitorAbstract {
$visitor = new class($exceptionVarName) extends NodeVisitorAbstract {
/**
* @var bool
*/
private $throwFound = false;

/**
* @var bool
*/
private $throwFoundProbably = false;

private $exceptionVarName;

public function __construct(string $exceptionVarName)
{
$this->exceptionVarName = $exceptionVarName;
}

public function leaveNode(Node $node)
{
// Only rethrow through static methods are allowed
if ($node instanceof StaticCall) {
$this->throwFoundProbably = $this->isProbablyAThrow($node);
}

if ($node instanceof Node\Stmt\Throw_) {
$this->throwFound = true;
}
Expand All @@ -71,6 +93,27 @@ public function isThrowFound(): bool
{
return $this->throwFound;
}

/**
* @return bool
*/
public function isThrowProbablyFound(): bool
{
return $this->throwFoundProbably;
}

private function isProbablyAThrow(Node $node)
{
if (!$args = $node->args) {
return false;
}

$varArgs = array_filter($args, function ($arg) {
return $arg->value instanceof Variable && $arg->value->name === $this->exceptionVarName ;
});

return 0 !== count($varArgs);
}
};

$traverser = new NodeTraverser();
Expand All @@ -81,7 +124,7 @@ public function isThrowFound(): bool

$errors = [];

if (!$visitor->isThrowFound()) {
if (!$visitor->isThrowFound() && !$visitor->isThrowProbablyFound()) {
$errors[] = sprintf('%scaught "%s" must be rethrown. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception. More info: http://bit.ly/failloud', PrefixGenerator::generatePrefix($scope), $exceptionType);
}

Expand Down