Skip to content

Commit b0e7a99

Browse files
authored
Report impure methods overriding @pure-unless-parameter-passed methods (#6666)
2 parents d86839d + 6fa0be6 commit b0e7a99

3 files changed

Lines changed: 113 additions & 0 deletions

File tree

‎src/Rules/Methods/MethodSignatureRule.php‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ public function processNode(Node $node, Scope $scope): array
9494
$parentMethodDeclaringClass->getDisplayName(),
9595
$parentMethod->getName(),
9696
))->identifier('method.impureOverridePureUnlessCallable')->build();
97+
} elseif (
98+
$this->reportMethodPurityOverride
99+
&& $method->isPure()->no()
100+
&& count($parentMethod->getPureUnlessParameterPassedParameters()) > 0
101+
) {
102+
$errors[] = RuleErrorBuilder::message(sprintf(
103+
'Impure method %s::%s() overrides method %s::%s() marked @pure-unless-parameter-passed.',
104+
$method->getDeclaringClass()->getDisplayName(),
105+
$method->getName(),
106+
$parentMethodDeclaringClass->getDisplayName(),
107+
$parentMethod->getName(),
108+
))->identifier('method.impureOverridePureUnlessParameterPassed')->build();
97109
}
98110

99111
$parentVariants = $parentMethod->getVariants();

‎tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,4 +659,21 @@ public function testPureUnlessCallableIsImpureOverride(): void
659659
]);
660660
}
661661

662+
public function testPureUnlessParameterPassedOverride(): void
663+
{
664+
$this->reportMaybes = true;
665+
$this->reportStatic = true;
666+
$this->reportMethodPurityOverride = true;
667+
$this->analyse([__DIR__ . '/data/method-signature-pure-unless-parameter-passed.php'], [
668+
[
669+
'Impure method MethodSignaturePureUnlessParameterPassed\ImpureChild::replace() overrides method MethodSignaturePureUnlessParameterPassed\PureUnlessParent::replace() marked @pure-unless-parameter-passed.',
670+
22,
671+
],
672+
[
673+
'Impure method MethodSignaturePureUnlessParameterPassed\AllMethodsImpureChild::replace() overrides method MethodSignaturePureUnlessParameterPassed\PureUnlessParent::replace() marked @pure-unless-parameter-passed.',
674+
76,
675+
],
676+
]);
677+
}
678+
662679
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace MethodSignaturePureUnlessParameterPassed;
4+
5+
interface PureUnlessParent
6+
{
7+
8+
/**
9+
* @param-out int $count
10+
* @pure-unless-parameter-passed $count
11+
*/
12+
public function replace(string $subject, int &$count = 0): string;
13+
14+
}
15+
16+
class ImpureChild implements PureUnlessParent
17+
{
18+
19+
/**
20+
* @phpstan-impure
21+
*/
22+
public function replace(string $subject, int &$count = 0): string
23+
{
24+
echo 'side effect';
25+
$count = 1;
26+
27+
return $subject;
28+
}
29+
30+
}
31+
32+
class InheritingChild implements PureUnlessParent
33+
{
34+
35+
public function replace(string $subject, int &$count = 0): string
36+
{
37+
$count = 1;
38+
39+
return $subject;
40+
}
41+
42+
}
43+
44+
class PureChild implements PureUnlessParent
45+
{
46+
47+
/**
48+
* @phpstan-pure
49+
*/
50+
public function replace(string $subject, int &$count = 0): string
51+
{
52+
return $subject;
53+
}
54+
55+
}
56+
57+
/**
58+
* @phpstan-all-methods-pure
59+
*/
60+
class AllMethodsPureChild implements PureUnlessParent
61+
{
62+
63+
public function replace(string $subject, int &$count = 0): string
64+
{
65+
return $subject;
66+
}
67+
68+
}
69+
70+
/**
71+
* @phpstan-all-methods-impure
72+
*/
73+
class AllMethodsImpureChild implements PureUnlessParent
74+
{
75+
76+
public function replace(string $subject, int &$count = 0): string
77+
{
78+
echo 'side effect';
79+
$count = 1;
80+
81+
return $subject;
82+
}
83+
84+
}

0 commit comments

Comments
 (0)