Skip to content

Commit 977b18e

Browse files
committed
for literal return true and return false, not for return $this->foo->doFoo()
1 parent 5c3bdba commit 977b18e

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

src/Rules/TooWideTypehints/TooWideTypeCheck.php

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

33
namespace PHPStan\Rules\TooWideTypehints;
44

5+
use PhpParser\Node\Expr\ConstFetch;
56
use PHPStan\Analyser\Scope;
67
use PHPStan\DependencyInjection\AutowiredParameter;
78
use PHPStan\DependencyInjection\AutowiredService;
@@ -13,6 +14,7 @@
1314
use PHPStan\Rules\IdentifierRuleError;
1415
use PHPStan\Rules\Properties\PropertyReflectionFinder;
1516
use PHPStan\Rules\RuleErrorBuilder;
17+
use PHPStan\TrinaryLogic;
1618
use PHPStan\Type\Constant\ConstantBooleanType;
1719
use PHPStan\Type\MixedType;
1820
use PHPStan\Type\NullType;
@@ -25,8 +27,10 @@
2527
use PHPStan\Type\VerbosityLevel;
2628
use PHPStan\Type\VoidType;
2729
use function count;
30+
use function in_array;
2831
use function lcfirst;
2932
use function sprintf;
33+
use function strtolower;
3034

3135
#[AutowiredService]
3236
final class TooWideTypeCheck
@@ -176,24 +180,25 @@ public function checkFunctionReturnType(
176180
if (count($returnStatements) === 0) {
177181
return [];
178182
}
179-
if (
180-
count($returnStatements) === 1
181-
&& (
182-
$nativeFunctionReturnType->isBoolean()->yes()
183-
|| $phpDocFunctionReturnType->isBoolean()->yes()
184-
)
185-
) {
186-
return [];
187-
}
188183

189184
$returnTypes = [];
185+
$returnsLiteralTrueFalse = [];
190186
foreach ($returnStatements as $returnStatement) {
191187
$returnNode = $returnStatement->getReturnNode();
192188
if ($returnNode->expr === null) {
193189
$returnTypes[] = new VoidType();
194190
continue;
195191
}
196192

193+
if (
194+
$returnNode->expr instanceof ConstFetch
195+
&& in_array(strtolower($returnNode->expr->name->toString()), ['true', 'false'], true)
196+
) {
197+
$returnsLiteralTrueFalse[] = TrinaryLogic::createYes();
198+
} else {
199+
$returnsLiteralTrueFalse[] = TrinaryLogic::createNo();
200+
}
201+
197202
$returnTypes[] = $returnStatement->getScope()->getType($returnNode->expr);
198203
}
199204

@@ -214,6 +219,18 @@ public function checkFunctionReturnType(
214219

215220
$returnType = TypeCombinator::union(...$returnTypes);
216221

222+
if (
223+
count($returnStatements) === 1
224+
&& $returnsLiteralTrueFalse !== []
225+
&& TrinaryLogic::extremeIdentity(...$returnsLiteralTrueFalse)->yes()
226+
&& (
227+
$nativeFunctionReturnType->isBoolean()->yes()
228+
|| $phpDocFunctionReturnType->isBoolean()->yes()
229+
)
230+
) {
231+
return [];
232+
}
233+
217234
$unionMessagePattern = sprintf('%s never returns %%s so it can be removed from the return type.', $functionDescription);
218235
$boolMessagePattern = sprintf('%s never returns %%s so the return type can be changed to %%s.', $functionDescription);
219236

tests/PHPStan/Rules/TooWideTypehints/TooWideFunctionReturnTypehintRuleTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ public function testBug13384cPhp82(): void
7777
{
7878
$this->reportTooWideBool = true;
7979
$this->reportNestedTooWideType = true;
80-
$this->analyse([__DIR__ . '/data/bug-13384c.php'], []);
80+
$this->analyse([__DIR__ . '/data/bug-13384c.php'], [
81+
[
82+
'Function Bug13384c\callsReturnsTrue() never returns false so the return type can be changed to true.',
83+
112,
84+
],
85+
]);
8186
}
8287

8388
#[RequiresPhp('< 8.2')]

tests/PHPStan/Rules/TooWideTypehints/data/bug-13384c.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,11 @@ function doFooPhpdoc2() {
104104
function doFooMixed() {
105105
return true;
106106
}
107+
108+
function returnsTrue(): true {
109+
return true;
110+
}
111+
112+
function callsReturnsTrue(): bool {
113+
return returnsTrue();
114+
}

0 commit comments

Comments
 (0)