Skip to content

Commit 0e695a4

Browse files
committed
Use TooWideTypeCheck in TooWideParameterOutTypeCheck
1 parent 5468ddd commit 0e695a4

File tree

7 files changed

+96
-39
lines changed

7 files changed

+96
-39
lines changed

src/Rules/TooWideTypehints/TooWideFunctionParameterOutTypeRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public function processNode(Node $node, Scope $scope): array
3232
$inFunction = $node->getFunctionReflection();
3333

3434
return $this->check->check(
35+
$node->getStartLine(),
3536
$node->getExecutionEnds(),
3637
$node->getReturnStatements(),
3738
$inFunction->getParameters(),

src/Rules/TooWideTypehints/TooWideMethodParameterOutTypeRule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public function processNode(Node $node, Scope $scope): array
4343
}
4444

4545
return $this->check->check(
46+
$node->getStartLine(),
4647
$node->getExecutionEnds(),
4748
$node->getReturnStatements(),
4849
$inMethod->getParameters(),

src/Rules/TooWideTypehints/TooWideParameterOutTypeCheck.php

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99
use PHPStan\Node\ReturnStatement;
1010
use PHPStan\Reflection\ExtendedParameterReflection;
1111
use PHPStan\Rules\IdentifierRuleError;
12-
use PHPStan\Rules\RuleErrorBuilder;
13-
use PHPStan\Type\TypeUtils;
14-
use PHPStan\Type\UnionType;
15-
use PHPStan\Type\VerbosityLevel;
1612
use function sprintf;
1713

1814
#[AutowiredService]
@@ -32,6 +28,7 @@ public function __construct(
3228
* @return list<IdentifierRuleError>
3329
*/
3430
public function check(
31+
int $startLine,
3532
array $executionEnds,
3633
array $returnStatements,
3734
array $parameters,
@@ -68,7 +65,7 @@ public function check(
6865
continue;
6966
}
7067

71-
foreach ($this->processSingleParameter($finalScope, $functionDescription, $parameter) as $error) {
68+
foreach ($this->processSingleParameter($startLine, $finalScope, $functionDescription, $parameter) as $error) {
7269
$errors[] = $error;
7370
}
7471
}
@@ -80,6 +77,7 @@ public function check(
8077
* @return list<IdentifierRuleError>
8178
*/
8279
private function processSingleParameter(
80+
int $startLine,
8381
Scope $scope,
8482
string $functionDescription,
8583
ExtendedParameterReflection $parameter,
@@ -95,18 +93,23 @@ private function processSingleParameter(
9593
$variableExpr = new Variable($parameter->getName());
9694
$variableType = $scope->getType($variableExpr);
9795

98-
/* sprintf(
99-
'%s never assigns %s to &$%s so it can be removed from the %s.',
100-
$functionDescription,
101-
$type->describe(VerbosityLevel::getRecommendedLevelByType($type)),
102-
$parameter->getName(),
103-
$isParamOutType ? '@param-out type' : 'by-ref type',
104-
) */
105-
10696
return $this->tooWideTypeCheck->checkParameterOutType(
10797
$outType,
10898
$variableType,
99+
sprintf(
100+
'%s never assigns %%s to &$%s so it can be removed from the %s.',
101+
$functionDescription,
102+
$parameter->getName(),
103+
$isParamOutType ? '@param-out type' : 'by-ref type',
104+
),
105+
sprintf(
106+
'%s never assigns %%s to &$%s so the %s can be changed to %%s.',
107+
$functionDescription,
108+
$parameter->getName(),
109+
$isParamOutType ? '@param-out type' : 'by-ref type',
110+
),
109111
$scope,
112+
$startLine,
110113
$isParamOutType ? 'paramOut' : 'parameterByRef',
111114
$isParamOutType ? null : 'You can narrow the parameter out type with @param-out PHPDoc tag.',
112115
);

src/Rules/TooWideTypehints/TooWideTypeCheck.php

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public function checkProperty(
9999
sprintf($boolMessagePattern, $propertyDescription, $phpDocPropertyTypeDescription),
100100
$node->getStartLine(),
101101
'property',
102+
null,
102103
);
103104
}
104105

@@ -116,6 +117,7 @@ public function checkProperty(
116117
sprintf($boolMessagePattern, $propertyDescription, $propertyTypeDescription),
117118
$node->getStartLine(),
118119
'property',
120+
null,
119121
);
120122
}
121123

@@ -177,7 +179,17 @@ public function checkFunctionReturnType(
177179

178180
if (!$phpDocFunctionReturnType instanceof MixedType || $phpDocFunctionReturnType->isExplicitMixed()) {
179181
$phpDocFunctionReturnType = TypeUtils::resolveLateResolvableTypes($phpDocFunctionReturnType);
180-
$narrowedPhpDocType = $this->narrowType($phpDocFunctionReturnType, $returnType, $scope, false);
182+
183+
// Do not require to have @return null/true/false in descendant classes
184+
if (
185+
$checkDescendantClass
186+
&& ($returnType->isNull()->yes() || $returnType->isTrue()->yes() || $returnType->isFalse()->yes())
187+
) {
188+
$narrowedPhpDocType = $phpDocFunctionReturnType;
189+
} else {
190+
$narrowedPhpDocType = $this->narrowType($phpDocFunctionReturnType, $returnType, $scope, false);
191+
}
192+
181193
if (!$narrowedPhpDocType->equals($phpDocFunctionReturnType)) {
182194
return $this->createErrors(
183195
$narrowedPhpDocType,
@@ -186,6 +198,7 @@ public function checkFunctionReturnType(
186198
$boolMessagePattern,
187199
$node->getStartLine(),
188200
'return',
201+
null,
189202
);
190203
}
191204

@@ -210,19 +223,24 @@ public function checkFunctionReturnType(
210223
$boolMessagePattern,
211224
$node->getStartLine(),
212225
'return',
226+
null,
213227
);
214228
}
215229

216230
return [];
217231
}
218232

219233
/**
234+
* @param 'paramOut'|'parameterByRef' $identifierPart
220235
* @return list<IdentifierRuleError>
221236
*/
222237
public function checkParameterOutType(
223238
Type $parameterOutType,
224239
Type $actualVariableType,
240+
string $unionMessagePattern,
241+
string $boolMessagePattern,
225242
Scope $scope,
243+
int $startLine,
226244
string $identifierPart,
227245
?string $tip,
228246
): array
@@ -238,13 +256,14 @@ public function checkParameterOutType(
238256
$parameterOutType,
239257
$unionMessagePattern,
240258
$boolMessagePattern,
241-
$node->getStartLine(),
259+
$startLine,
242260
$identifierPart,
261+
$tip,
243262
);
244263
}
245264

246265
/**
247-
* @param 'return'|'property' $identifierPart
266+
* @param 'return'|'property'|'paramOut'|'parameterByRef' $identifierPart
248267
* @return list<IdentifierRuleError>
249268
*/
250269
private function createErrors(
@@ -254,18 +273,22 @@ private function createErrors(
254273
string $boolMessagePattern,
255274
int $startLine,
256275
string $identifierPart,
276+
?string $tip,
257277
): array
258278
{
259279
if ($originalType->isBoolean()->yes()) {
260280
$neverReturns = $narrowedType->isTrue()->yes() ? new ConstantBooleanType(false) : new ConstantBooleanType(true);
261281

262-
return [
263-
RuleErrorBuilder::message(sprintf(
264-
$boolMessagePattern,
265-
$neverReturns->describe(VerbosityLevel::getRecommendedLevelByType($neverReturns)),
266-
$narrowedType->describe(VerbosityLevel::getRecommendedLevelByType($narrowedType)),
267-
))->identifier(sprintf('%s.tooWideBool', $identifierPart))->line($startLine)->build(),
268-
];
282+
$errorBuilder = RuleErrorBuilder::message(sprintf(
283+
$boolMessagePattern,
284+
$neverReturns->describe(VerbosityLevel::getRecommendedLevelByType($neverReturns)),
285+
$narrowedType->describe(VerbosityLevel::getRecommendedLevelByType($narrowedType)),
286+
))->identifier(sprintf('%s.tooWideBool', $identifierPart))->line($startLine);
287+
if ($tip !== null) {
288+
$errorBuilder->tip($tip);
289+
}
290+
291+
return [$errorBuilder->build()];
269292
}
270293

271294
if (!$originalType instanceof UnionType) {
@@ -278,10 +301,15 @@ private function createErrors(
278301
continue;
279302
}
280303

281-
$messages[] = RuleErrorBuilder::message(sprintf(
304+
$errorBuilder = RuleErrorBuilder::message(sprintf(
282305
$unionMessagePattern,
283306
$innerType->describe(VerbosityLevel::getRecommendedLevelByType($innerType)),
284-
))->identifier(sprintf('%s.unusedType', $identifierPart))->line($startLine)->build();
307+
))->identifier(sprintf('%s.unusedType', $identifierPart))->line($startLine);
308+
if ($tip !== null) {
309+
$errorBuilder->tip($tip);
310+
}
311+
312+
$messages[] = $errorBuilder->build();
285313
}
286314

287315
return $messages;

tests/PHPStan/Rules/TooWideTypehints/TooWideFunctionParameterOutTypeRuleTest.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\TooWideTypehints;
44

5+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
56
use PHPStan\Rules\Rule as TRule;
67
use PHPStan\Testing\RuleTestCase;
78

@@ -13,7 +14,9 @@ class TooWideFunctionParameterOutTypeRuleTest extends RuleTestCase
1314

1415
protected function getRule(): TRule
1516
{
16-
return new TooWideFunctionParameterOutTypeRule(new TooWideParameterOutTypeCheck());
17+
return new TooWideFunctionParameterOutTypeRule(new TooWideParameterOutTypeCheck(
18+
new TooWideTypeCheck(new PropertyReflectionFinder(), true),
19+
));
1720
}
1821

1922
public function testRule(): void
@@ -33,10 +36,6 @@ public function testRule(): void
3336
23,
3437
'You can narrow the parameter out type with @param-out PHPDoc tag.',
3538
],
36-
[
37-
'Function TooWideFunctionParameterOut\bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
38-
48,
39-
],
4039
]);
4140
}
4241

tests/PHPStan/Rules/TooWideTypehints/TooWideMethodParameterOutTypeRuleTest.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Rules\TooWideTypehints;
44

5+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
56
use PHPStan\Rules\Rule as TRule;
67
use PHPStan\Testing\RuleTestCase;
78

@@ -15,7 +16,12 @@ class TooWideMethodParameterOutTypeRuleTest extends RuleTestCase
1516

1617
protected function getRule(): TRule
1718
{
18-
return new TooWideMethodParameterOutTypeRule(new TooWideParameterOutTypeCheck(), $this->checkProtectedAndPublicMethods);
19+
return new TooWideMethodParameterOutTypeRule(
20+
new TooWideParameterOutTypeCheck(
21+
new TooWideTypeCheck(new PropertyReflectionFinder(), true),
22+
),
23+
$this->checkProtectedAndPublicMethods,
24+
);
1925
}
2026

2127
public function testRule(): void
@@ -35,10 +41,6 @@ public function testRule(): void
3541
26,
3642
'You can narrow the parameter out type with @param-out PHPDoc tag.',
3743
],
38-
[
39-
'Method TooWideMethodParameterOut\Foo::bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
40-
37,
41-
],
4244
[
4345
'Method TooWideMethodParameterOut\Foo::finalDoBaz() never assigns null to &$p so it can be removed from the @param-out type.',
4446
45,
@@ -66,8 +68,13 @@ public function testRule(): void
6668
'You can narrow the parameter out type with @param-out PHPDoc tag.',
6769
],
6870
[
69-
'Method TooWideMethodParameterOut\FinalFoo::bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
70-
100,
71+
'Method TooWideMethodParameterOut\FinalFoo::doBool() never assigns false to &$b so the by-ref type can be changed to true.',
72+
105,
73+
'You can narrow the parameter out type with @param-out PHPDoc tag.',
74+
],
75+
[
76+
'Method TooWideMethodParameterOut\FinalFoo::doBool2() never assigns false to &$b so the @param-out type can be changed to true.',
77+
113,
7178
],
7279
]);
7380
}
@@ -99,8 +106,13 @@ public function testRuleWithoutProtectedAndPublic(): void
99106
'You can narrow the parameter out type with @param-out PHPDoc tag.',
100107
],
101108
[
102-
'Method TooWideMethodParameterOut\FinalFoo::bug10699() never assigns 20 to &$out so it can be removed from the @param-out type.',
103-
100,
109+
'Method TooWideMethodParameterOut\FinalFoo::doBool() never assigns false to &$b so the by-ref type can be changed to true.',
110+
105,
111+
'You can narrow the parameter out type with @param-out PHPDoc tag.',
112+
],
113+
[
114+
'Method TooWideMethodParameterOut\FinalFoo::doBool2() never assigns false to &$b so the @param-out type can be changed to true.',
115+
113,
104116
],
105117
]);
106118
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,17 @@ function bug10699(int $flags, &$out): void
102102

103103
}
104104

105+
public function doBool(bool &$b): void
106+
{
107+
$b = true;
108+
}
109+
110+
/**
111+
* @param-out bool $b
112+
*/
113+
public function doBool2(bool &$b): void
114+
{
115+
$b = true;
116+
}
117+
105118
}

0 commit comments

Comments
 (0)