Skip to content

Commit 802fa6e

Browse files
committed
Report always true/false comparison against null only for native properties without native type
1 parent a06db02 commit 802fa6e

File tree

5 files changed

+46
-23
lines changed

5 files changed

+46
-23
lines changed

src/Analyser/MutatingScope.php

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,23 +2781,6 @@ private function promoteNativeTypes(): self
27812781
);
27822782
}
27832783

2784-
/**
2785-
* @param Node\Expr\PropertyFetch|Node\Expr\StaticPropertyFetch $propertyFetch
2786-
*/
2787-
public function hasPropertyNativeType($propertyFetch): bool
2788-
{
2789-
$propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyFetch, $this);
2790-
if ($propertyReflection === null) {
2791-
return false;
2792-
}
2793-
2794-
if (!$propertyReflection->isNative()) {
2795-
return false;
2796-
}
2797-
2798-
return $propertyReflection->hasNativeType();
2799-
}
2800-
28012784
private function getTypeFromArrayDimFetch(
28022785
Expr\ArrayDimFetch $arrayDimFetch,
28032786
Type $offsetType,

src/Analyser/RicherScopeGetTypeHelper.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpParser\Node\Expr\Variable;
88
use PHPStan\DependencyInjection\AutowiredService;
99
use PHPStan\Reflection\InitializerExprTypeResolver;
10+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
1011
use PHPStan\Type\BooleanType;
1112
use PHPStan\Type\Constant\ConstantBooleanType;
1213
use PHPStan\Type\TypeResult;
@@ -16,7 +17,10 @@
1617
final class RicherScopeGetTypeHelper
1718
{
1819

19-
public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver)
20+
public function __construct(
21+
private InitializerExprTypeResolver $initializerExprTypeResolver,
22+
private PropertyReflectionFinder $propertyReflectionFinder,
23+
)
2024
{
2125
}
2226

@@ -48,9 +52,13 @@ public function getIdenticalResult(Scope $scope, Identical $expr): TypeResult
4852
|| $expr->left instanceof Node\Expr\StaticPropertyFetch
4953
)
5054
&& $rightType->isNull()->yes()
51-
&& !$scope->hasPropertyNativeType($expr->left)
5255
) {
53-
return new TypeResult(new BooleanType(), []);
56+
$foundPropertyReflections = $this->propertyReflectionFinder->findPropertyReflectionsFromNode($expr->left, $scope);
57+
foreach ($foundPropertyReflections as $foundPropertyReflection) {
58+
if ($foundPropertyReflection->isNative() && !$foundPropertyReflection->hasNativeType()) {
59+
return new TypeResult(new BooleanType(), []);
60+
}
61+
}
5462
}
5563

5664
if (
@@ -59,9 +67,13 @@ public function getIdenticalResult(Scope $scope, Identical $expr): TypeResult
5967
|| $expr->right instanceof Node\Expr\StaticPropertyFetch
6068
)
6169
&& $leftType->isNull()->yes()
62-
&& !$scope->hasPropertyNativeType($expr->right)
6370
) {
64-
return new TypeResult(new BooleanType(), []);
71+
$foundPropertyReflections = $this->propertyReflectionFinder->findPropertyReflectionsFromNode($expr->right, $scope);
72+
foreach ($foundPropertyReflections as $foundPropertyReflection) {
73+
if ($foundPropertyReflection->isNative() && !$foundPropertyReflection->hasNativeType()) {
74+
return new TypeResult(new BooleanType(), []);
75+
}
76+
}
6577
}
6678

6779
return $this->initializerExprTypeResolver->resolveIdenticalType($leftType, $rightType);

src/Testing/PHPStanTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider
162162
new PropertyReflectionFinder(),
163163
self::getParser(),
164164
$container->getByType(NodeScopeResolver::class),
165-
new RicherScopeGetTypeHelper($initializerExprTypeResolver),
165+
new RicherScopeGetTypeHelper($initializerExprTypeResolver, new PropertyReflectionFinder()),
166166
$container->getByType(PhpVersion::class),
167167
$container->getByType(AttributeReflectionFactory::class),
168168
$container->getParameter('phpVersion'),

tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,4 +1029,15 @@ public function testBug13208(): void
10291029
$this->analyse([__DIR__ . '/data/bug-13208.php'], []);
10301030
}
10311031

1032+
public function testBug11609(): void
1033+
{
1034+
$this->analyse([__DIR__ . '/data/bug-11609.php'], [
1035+
[
1036+
'Strict comparison using !== between string and null will always evaluate to true.',
1037+
10,
1038+
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
1039+
],
1040+
]);
1041+
}
1042+
10321043
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Bug11609;
4+
5+
class HelloWorld
6+
{
7+
/** @param object{hello: string, world?: string} $a */
8+
public function sayHello(object $a, string $b): void
9+
{
10+
if ($a->hello !== null) {
11+
echo 'hello';
12+
}
13+
if ($a->world !== null) {
14+
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)