Skip to content

Commit ba8e4f0

Browse files
Introduce checkTooWideParameterOutInProtectedAndPublicMethods
1 parent 745ae5a commit ba8e4f0

File tree

6 files changed

+166
-1
lines changed

6 files changed

+166
-1
lines changed

conf/config.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ parameters:
5454
checkPhpDocMethodSignatures: false
5555
checkExtraArguments: false
5656
checkMissingTypehints: false
57+
checkTooWideParameterOutInProtectedAndPublicMethods: false
5758
checkTooWideReturnTypesInProtectedAndPublicMethods: false
5859
checkUninitializedProperties: false
5960
checkDynamicProperties: false

conf/parametersSchema.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ parametersSchema:
5858
checkPhpDocMethodSignatures: bool()
5959
checkExtraArguments: bool()
6060
checkMissingTypehints: bool()
61+
checkTooWideParameterOutInProtectedAndPublicMethods: bool()
6162
checkTooWideReturnTypesInProtectedAndPublicMethods: bool()
6263
checkUninitializedProperties: bool()
6364
checkDynamicProperties: bool()

src/Rules/TooWideTypehints/TooWideMethodParameterOutTypeRule.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
7+
use PHPStan\DependencyInjection\AutowiredParameter;
78
use PHPStan\DependencyInjection\RegisteredRule;
89
use PHPStan\Node\MethodReturnStatementsNode;
910
use PHPStan\Rules\Rule;
@@ -18,6 +19,8 @@ final class TooWideMethodParameterOutTypeRule implements Rule
1819

1920
public function __construct(
2021
private TooWideParameterOutTypeCheck $check,
22+
#[AutowiredParameter(ref: '%checkTooWideParameterOutInProtectedAndPublicMethods%')]
23+
private bool $checkProtectedAndPublicMethods,
2124
)
2225
{
2326
}
@@ -31,6 +34,14 @@ public function processNode(Node $node, Scope $scope): array
3134
{
3235
$inMethod = $node->getMethodReflection();
3336

37+
if (!$inMethod->isPrivate()) {
38+
if (!$inMethod->getDeclaringClass()->isFinal() && !$inMethod->isFinal()->yes()) {
39+
if (!$this->checkProtectedAndPublicMethods) {
40+
return [];
41+
}
42+
}
43+
}
44+
3445
return $this->check->check(
3546
$node->getExecutionEnds(),
3647
$node->getReturnStatements(),

tests/PHPStan/Rules/TooWideTypehints/TooWideMethodParameterOutTypeRuleTest.php

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
class TooWideMethodParameterOutTypeRuleTest extends RuleTestCase
1212
{
1313

14+
private bool $checkProtectedAndPublicMethods = true;
15+
1416
protected function getRule(): TRule
1517
{
16-
return new TooWideMethodParameterOutTypeRule(new TooWideParameterOutTypeCheck());
18+
return new TooWideMethodParameterOutTypeRule(new TooWideParameterOutTypeCheck(), $this->checkProtectedAndPublicMethods);
1719
}
1820

1921
public function testRule(): void
@@ -37,6 +39,69 @@ public function testRule(): void
3739
'Method TooWideMethodParameterOut\Foo::bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
3840
37,
3941
],
42+
[
43+
'Method TooWideMethodParameterOut\Foo::finalDoBaz() never assigns null to &$p so it can be removed from the @param-out type.',
44+
45,
45+
],
46+
[
47+
'Method TooWideMethodParameterOut\Foo::doBazProtected() never assigns null to &$p so it can be removed from the @param-out type.',
48+
53,
49+
],
50+
[
51+
'Method TooWideMethodParameterOut\Foo::doBazPrivate() never assigns null to &$p so it can be removed from the @param-out type.',
52+
61,
53+
],
54+
[
55+
'Method TooWideMethodParameterOut\FinalFoo::doBar() never assigns null to &$p so it can be removed from the by-ref type.',
56+
76,
57+
'You can narrow the parameter out type with @param-out PHPDoc tag.',
58+
],
59+
[
60+
'Method TooWideMethodParameterOut\FinalFoo::doBaz() never assigns null to &$p so it can be removed from the @param-out type.',
61+
84,
62+
],
63+
[
64+
'Method TooWideMethodParameterOut\FinalFoo::doLorem() never assigns null to &$p so it can be removed from the by-ref type.',
65+
89,
66+
'You can narrow the parameter out type with @param-out PHPDoc tag.',
67+
],
68+
[
69+
'Method TooWideMethodParameterOut\FinalFoo::bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
70+
100,
71+
],
72+
]);
73+
}
74+
75+
public function testRuleWithoutProtectedAndPublic(): void
76+
{
77+
$this->checkProtectedAndPublicMethods = false;
78+
$this->analyse([__DIR__ . '/data/too-wide-method-parameter-out.php'], [
79+
[
80+
'Method TooWideMethodParameterOut\Foo::finalDoBaz() never assigns null to &$p so it can be removed from the @param-out type.',
81+
45,
82+
],
83+
[
84+
'Method TooWideMethodParameterOut\Foo::doBazPrivate() never assigns null to &$p so it can be removed from the @param-out type.',
85+
61,
86+
],
87+
[
88+
'Method TooWideMethodParameterOut\FinalFoo::doBar() never assigns null to &$p so it can be removed from the by-ref type.',
89+
76,
90+
'You can narrow the parameter out type with @param-out PHPDoc tag.',
91+
],
92+
[
93+
'Method TooWideMethodParameterOut\FinalFoo::doBaz() never assigns null to &$p so it can be removed from the @param-out type.',
94+
84,
95+
],
96+
[
97+
'Method TooWideMethodParameterOut\FinalFoo::doLorem() never assigns null to &$p so it can be removed from the by-ref type.',
98+
89,
99+
'You can narrow the parameter out type with @param-out PHPDoc tag.',
100+
],
101+
[
102+
'Method TooWideMethodParameterOut\FinalFoo::bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
103+
100,
104+
],
40105
]);
41106
}
42107

@@ -50,4 +115,10 @@ public function testBug10687(): void
50115
$this->analyse([__DIR__ . '/data/bug-10687.php'], []);
51116
}
52117

118+
public function testBug12080(): void
119+
{
120+
$this->checkProtectedAndPublicMethods = false;
121+
$this->analyse([__DIR__ . '/data/bug-12080.php'], []);
122+
}
123+
53124
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Bug12080;
4+
5+
class C {
6+
/**
7+
* @param mixed $x
8+
* @param-out string|int $x
9+
*/
10+
public function foo(&$x): void {
11+
$x = "foo";
12+
}
13+
}
14+
15+
class D extends C {
16+
public function foo(&$x): void {
17+
$x = 42;
18+
}
19+
}

tests/PHPStan/Rules/TooWideTypehints/data/too-wide-method-parameter-out.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,67 @@ function bug10699(int $flags, &$out): void
3939

4040
}
4141

42+
/**
43+
* @param-out string|null $p
44+
*/
45+
final public function finalDoBaz(?string &$p): void
46+
{
47+
$p = 'foo';
48+
}
49+
50+
/**
51+
* @param-out string|null $p
52+
*/
53+
protected function doBazProtected(?string &$p): void
54+
{
55+
$p = 'foo';
56+
}
57+
58+
/**
59+
* @param-out string|null $p
60+
*/
61+
private function doBazPrivate(?string &$p): void
62+
{
63+
$p = 'foo';
64+
}
65+
66+
}
67+
68+
final class FinalFoo
69+
{
70+
71+
public function doFoo(?string &$p): void
72+
{
73+
74+
}
75+
76+
public function doBar(?string &$p): void
77+
{
78+
$p = 'foo';
79+
}
80+
81+
/**
82+
* @param-out string|null $p
83+
*/
84+
public function doBaz(?string &$p): void
85+
{
86+
$p = 'foo';
87+
}
88+
89+
public function doLorem(?string &$p): void
90+
{
91+
$p = 'foo';
92+
}
93+
94+
/**
95+
* @param int $flags
96+
* @param 10 $out
97+
*
98+
* @param-out ($flags is 2 ? 20 : 10) $out
99+
*/
100+
function bug10699(int $flags, &$out): void
101+
{
102+
103+
}
42104

43105
}

0 commit comments

Comments
 (0)