Skip to content

Commit

Permalink
Detect unused constructor method calls
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Nov 1, 2020
1 parent 25d5715 commit 21c50e3
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 0 deletions.
1 change: 1 addition & 0 deletions conf/config.level4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ rules:
- PHPStan\Rules\DeadCode\UnreachableStatementRule
- PHPStan\Rules\Exceptions\DeadCatchRule
- PHPStan\Rules\Functions\CallToFunctionStamentWithoutSideEffectsRule
- PHPStan\Rules\Methods\CallToConstructorStatementWithoutSideEffectsRule
- PHPStan\Rules\Methods\CallToMethodStamentWithoutSideEffectsRule
- PHPStan\Rules\Methods\CallToStaticMethodStamentWithoutSideEffectsRule
- PHPStan\Rules\TooWideTypehints\TooWideArrowFunctionReturnTypehintRule
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Methods;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

/**
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\Expression>
*/
class CallToConstructorStatementWithoutSideEffectsRule implements Rule
{

private ReflectionProvider $reflectionProvider;

public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
}

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

public function processNode(Node $node, Scope $scope): array
{
if (!$node->expr instanceof Node\Expr\New_) {
return [];
}

$instantiation = $node->expr;
if (!$instantiation->class instanceof Node\Name) {
return [];
}

$className = $scope->resolveName($instantiation->class);
if (!$this->reflectionProvider->hasClass($className)) {
return [];
}

$classReflection = $this->reflectionProvider->getClass($className);
if (!$classReflection->hasConstructor()) {
return [];
}

$constructor = $classReflection->getConstructor();
if ($constructor->hasSideEffects()->no()) {
return [
RuleErrorBuilder::message(sprintf(
'Call to %s::%s() on a separate line has no effect.',
$classReflection->getDisplayName(),
$constructor->getName()
))->build(),
];
}

return [];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Methods;

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

/**
* @extends RuleTestCase<CallToConstructorStatementWithoutSideEffectsRule>
*/
class CallToConstructorStatementWithoutSideEffectsRuleTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new CallToConstructorStatementWithoutSideEffectsRule($this->createReflectionProvider());
}

public function testRule(): void
{
$this->analyse([__DIR__ . '/data/constructor-statement-no-side-effects.php'], [
[
'Call to Exception::__construct() on a separate line has no effect.',
6,
],
]);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace ConstructorStatementNoSideEffects;

function () {
new \Exception();
throw new \Exception();
};

function () {
new \PDOStatement();
new \stdClass();
};

0 comments on commit 21c50e3

Please sign in to comment.