Skip to content

Commit 2e27573

Browse files
Update PhpStorm stubs + refactor WithoutSideEffectsRule classes
Co-authored-by: ondrejmirtes <[email protected]>
1 parent d528228 commit 2e27573

6 files changed

+61
-92
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"hoa/compiler": "3.17.08.08",
1616
"hoa/exception": "^1.0",
1717
"hoa/file": "1.17.07.11",
18-
"jetbrains/phpstorm-stubs": "dev-master#bdc8acd7c04c0c87197849c7cdd27e44b67b56c7",
18+
"jetbrains/phpstorm-stubs": "dev-master#5686f9ceebde3d9338bea53b78d70ebde5fb5710",
1919
"nette/bootstrap": "^3.0",
2020
"nette/di": "^3.1.4",
2121
"nette/neon": "3.3.3",

composer.lock

+9-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php

+15-23
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44

55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
7+
use PHPStan\Node\NoopExpressionNode;
78
use PHPStan\Reflection\ReflectionProvider;
89
use PHPStan\Rules\Rule;
910
use PHPStan\Rules\RuleErrorBuilder;
1011
use PHPStan\Type\NeverType;
1112
use function sprintf;
1213

1314
/**
14-
* @implements Rule<Node\Stmt\Expression>
15+
* @implements Rule<NoopExpressionNode>
1516
*/
1617
final class CallToConstructorStatementWithoutSideEffectsRule implements Rule
1718
{
@@ -25,16 +26,16 @@ public function __construct(
2526

2627
public function getNodeType(): string
2728
{
28-
return Node\Stmt\Expression::class;
29+
return NoopExpressionNode::class;
2930
}
3031

3132
public function processNode(Node $node, Scope $scope): array
3233
{
33-
if (!$node->expr instanceof Node\Expr\New_) {
34+
$instantiation = $node->getOriginalExpr();
35+
if (!$instantiation instanceof Node\Expr\New_) {
3436
return [];
3537
}
3638

37-
$instantiation = $node->expr;
3839
if (!$instantiation->class instanceof Node\Name) {
3940
return [];
4041
}
@@ -59,27 +60,18 @@ public function processNode(Node $node, Scope $scope): array
5960
}
6061

6162
$constructor = $classReflection->getConstructor();
62-
if ($constructor->hasSideEffects()->no()) {
63-
$throwsType = $constructor->getThrowType();
64-
if ($throwsType !== null && !$throwsType->isVoid()->yes()) {
65-
return [];
66-
}
67-
68-
$methodResult = $scope->getType($instantiation);
69-
if ($methodResult instanceof NeverType && $methodResult->isExplicit()) {
70-
return [];
71-
}
72-
73-
return [
74-
RuleErrorBuilder::message(sprintf(
75-
'Call to %s::%s() on a separate line has no effect.',
76-
$classReflection->getDisplayName(),
77-
$constructor->getName(),
78-
))->identifier('new.resultUnused')->build(),
79-
];
63+
$methodResult = $scope->getType($instantiation);
64+
if ($methodResult instanceof NeverType && $methodResult->isExplicit()) {
65+
return [];
8066
}
8167

82-
return [];
68+
return [
69+
RuleErrorBuilder::message(sprintf(
70+
'Call to %s::%s() on a separate line has no effect.',
71+
$classReflection->getDisplayName(),
72+
$constructor->getName(),
73+
))->identifier('new.resultUnused')->build(),
74+
];
8375
}
8476

8577
}

src/Rules/Methods/CallToMethodStatementWithoutSideEffectsRule.php

+20-29
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\NullsafeOperatorHelper;
77
use PHPStan\Analyser\Scope;
8+
use PHPStan\Node\NoopExpressionNode;
89
use PHPStan\Rules\Rule;
910
use PHPStan\Rules\RuleErrorBuilder;
1011
use PHPStan\Rules\RuleLevelHelper;
@@ -14,7 +15,7 @@
1415
use function sprintf;
1516

1617
/**
17-
* @implements Rule<Node\Stmt\Expression>
18+
* @implements Rule<NoopExpressionNode>
1819
*/
1920
final class CallToMethodStatementWithoutSideEffectsRule implements Rule
2021
{
@@ -25,18 +26,18 @@ public function __construct(private RuleLevelHelper $ruleLevelHelper)
2526

2627
public function getNodeType(): string
2728
{
28-
return Node\Stmt\Expression::class;
29+
return NoopExpressionNode::class;
2930
}
3031

3132
public function processNode(Node $node, Scope $scope): array
3233
{
33-
if ($node->expr instanceof Node\Expr\NullsafeMethodCall) {
34-
$scope = $scope->filterByTruthyValue(new Node\Expr\BinaryOp\NotIdentical($node->expr->var, new Node\Expr\ConstFetch(new Node\Name('null'))));
35-
} elseif (!$node->expr instanceof Node\Expr\MethodCall) {
34+
$methodCall = $node->getOriginalExpr();
35+
if ($methodCall instanceof Node\Expr\NullsafeMethodCall) {
36+
$scope = $scope->filterByTruthyValue(new Node\Expr\BinaryOp\NotIdentical($methodCall->var, new Node\Expr\ConstFetch(new Node\Name('null'))));
37+
} elseif (!$methodCall instanceof Node\Expr\MethodCall) {
3638
return [];
3739
}
3840

39-
$methodCall = $node->expr;
4041
if (!$methodCall->name instanceof Node\Identifier) {
4142
return [];
4243
}
@@ -60,31 +61,21 @@ public function processNode(Node $node, Scope $scope): array
6061
return [];
6162
}
6263

63-
$method = $calledOnType->getMethod($methodName, $scope);
64-
if ($method->hasSideEffects()->no() || $node->expr->isFirstClassCallable()) {
65-
if (!$node->expr->isFirstClassCallable()) {
66-
$throwsType = $method->getThrowType();
67-
if ($throwsType !== null && !$throwsType->isVoid()->yes()) {
68-
return [];
69-
}
70-
}
71-
72-
$methodResult = $scope->getType($methodCall);
73-
if ($methodResult instanceof NeverType && $methodResult->isExplicit()) {
74-
return [];
75-
}
76-
77-
return [
78-
RuleErrorBuilder::message(sprintf(
79-
'Call to %s %s::%s() on a separate line has no effect.',
80-
$method->isStatic() ? 'static method' : 'method',
81-
$method->getDeclaringClass()->getDisplayName(),
82-
$method->getName(),
83-
))->identifier('method.resultUnused')->build(),
84-
];
64+
$methodResult = $scope->getType($methodCall);
65+
if ($methodResult instanceof NeverType && $methodResult->isExplicit()) {
66+
return [];
8567
}
8668

87-
return [];
69+
$method = $calledOnType->getMethod($methodName, $scope);
70+
71+
return [
72+
RuleErrorBuilder::message(sprintf(
73+
'Call to %s %s::%s() on a separate line has no effect.',
74+
$method->isStatic() ? 'static method' : 'method',
75+
$method->getDeclaringClass()->getDisplayName(),
76+
$method->getName(),
77+
))->identifier('method.resultUnused')->build(),
78+
];
8879
}
8980

9081
}

src/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRule.php

+16-26
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\NullsafeOperatorHelper;
77
use PHPStan\Analyser\Scope;
8+
use PHPStan\Node\NoopExpressionNode;
89
use PHPStan\Reflection\ReflectionProvider;
910
use PHPStan\Rules\Rule;
1011
use PHPStan\Rules\RuleErrorBuilder;
@@ -17,7 +18,7 @@
1718
use function strtolower;
1819

1920
/**
20-
* @implements Rule<Node\Stmt\Expression>
21+
* @implements Rule<NoopExpressionNode>
2122
*/
2223
final class CallToStaticMethodStatementWithoutSideEffectsRule implements Rule
2324
{
@@ -31,16 +32,16 @@ public function __construct(
3132

3233
public function getNodeType(): string
3334
{
34-
return Node\Stmt\Expression::class;
35+
return NoopExpressionNode::class;
3536
}
3637

3738
public function processNode(Node $node, Scope $scope): array
3839
{
39-
if (!$node->expr instanceof Node\Expr\StaticCall) {
40+
$staticCall = $node->getOriginalExpr();
41+
if (!$staticCall instanceof Node\Expr\StaticCall) {
4042
return [];
4143
}
4244

43-
$staticCall = $node->expr;
4445
if (!$staticCall->name instanceof Node\Identifier) {
4546
return [];
4647
}
@@ -84,30 +85,19 @@ public function processNode(Node $node, Scope $scope): array
8485
return [];
8586
}
8687

87-
if ($method->hasSideEffects()->no() || $node->expr->isFirstClassCallable()) {
88-
if (!$node->expr->isFirstClassCallable()) {
89-
$throwsType = $method->getThrowType();
90-
if ($throwsType !== null && !$throwsType->isVoid()->yes()) {
91-
return [];
92-
}
93-
}
94-
95-
$methodResult = $scope->getType($staticCall);
96-
if ($methodResult instanceof NeverType && $methodResult->isExplicit()) {
97-
return [];
98-
}
99-
100-
return [
101-
RuleErrorBuilder::message(sprintf(
102-
'Call to %s %s::%s() on a separate line has no effect.',
103-
$method->isStatic() ? 'static method' : 'method',
104-
$method->getDeclaringClass()->getDisplayName(),
105-
$method->getName(),
106-
))->identifier('staticMethod.resultUnused')->build(),
107-
];
88+
$methodResult = $scope->getType($staticCall);
89+
if ($methodResult instanceof NeverType && $methodResult->isExplicit()) {
90+
return [];
10891
}
10992

110-
return [];
93+
return [
94+
RuleErrorBuilder::message(sprintf(
95+
'Call to %s %s::%s() on a separate line has no effect.',
96+
$method->isStatic() ? 'static method' : 'method',
97+
$method->getDeclaringClass()->getDisplayName(),
98+
$method->getName(),
99+
))->identifier('staticMethod.resultUnused')->build(),
100+
];
111101
}
112102

113103
}

tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php

-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ public function testRule(): void
2828
'Call to static method DateTimeImmutable::createFromFormat() on a separate line has no effect.',
2929
12,
3030
],
31-
[
32-
'Call to static method DateTimeImmutable::createFromFormat() on a separate line has no effect.',
33-
13,
34-
],
3531
[
3632
'Call to method DateTime::format() on a separate line has no effect.',
3733
23,

0 commit comments

Comments
 (0)