From 644e92394f744fdbea20344329403f8bc2c8522b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:19:24 +0000 Subject: [PATCH] Fix false positives for is_a() and instanceof checks on $this in traits - When analyzing trait methods, $this is bound to each using class separately - is_a($this, SomeClass::class) was reported as "always true" in SomeClass context and "always false" in SomeClass2 context, but both are false positives - Added trait-aware check in ImpossibleCheckTypeHelper to treat $this as uncertain when inside a trait, since the same code is shared across multiple classes - New regression test in tests/PHPStan/Rules/Comparison/data/bug-13023.php Closes https://github.com/phpstan/phpstan/issues/13023 --- .../Comparison/ImpossibleCheckTypeHelper.php | 10 ++++++++ ...mpossibleCheckTypeFunctionCallRuleTest.php | 6 +++++ .../Rules/Comparison/data/bug-13023.php | 25 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/PHPStan/Rules/Comparison/data/bug-13023.php diff --git a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php index 97a0179405..49429d1abb 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php @@ -310,6 +310,11 @@ public function findSpecifiedType( continue; } + if ($scope->isInTrait() && $sureType[0] instanceof Expr\Variable && $sureType[0]->name === 'this') { + $results[] = TrinaryLogic::createMaybe(); + continue; + } + if ($this->treatPhpDocTypesAsCertain) { $argumentType = $scope->getType($sureType[0]); } else { @@ -336,6 +341,11 @@ public function findSpecifiedType( continue; } + if ($scope->isInTrait() && $sureNotType[0] instanceof Expr\Variable && $sureNotType[0]->name === 'this') { + $results[] = TrinaryLogic::createMaybe(); + continue; + } + if ($this->treatPhpDocTypesAsCertain) { $argumentType = $scope->getType($sureNotType[0]); } else { diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index 69e992139d..8f0f4843c2 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -1207,4 +1207,10 @@ public function testBug13799(): void ]); } + public function testBug13023(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-13023.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-13023.php b/tests/PHPStan/Rules/Comparison/data/bug-13023.php new file mode 100644 index 0000000000..cba8bf0226 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-13023.php @@ -0,0 +1,25 @@ +