From fcdfa63acbbfde84e6a559f7bfd67c07cdf9f2fd Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Wed, 11 Dec 2024 15:38:26 +0000 Subject: [PATCH 1/7] Add support for internal classes that overload offset access --- src/Type/ObjectType.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 9c633d62da..fab7c056b0 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -67,7 +67,19 @@ class ObjectType implements TypeWithClassName, SubtractableType use UndecidedComparisonTypeTrait; use NonGeneralizableTypeTrait; - private const EXTRA_OFFSET_CLASSES = ['SimpleXMLElement', 'DOMNodeList', 'Threaded']; + private const EXTRA_OFFSET_CLASSES = [ + 'DOMNamedNodeMap', // Only read and existence + 'Dom\NamedNodeMap', // Only read and existence + 'DOMNodeList', // Only read and existence + 'Dom\NodeList', // Only read and existence + 'Dom\HTMLCollection', // Only read and existence + 'Dom\DtdNamedNodeMap', // Only read and existence + 'PDORow', // Only read and existence + 'ResourceBundle', // Only read + 'FFI\CData', // Very funky and weird + 'SimpleXMLElement', + 'Threaded', + ]; private ?Type $subtractedType; From bff963c0c5f498d310360c42715ae5eaf3d205ab Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 12 Dec 2024 04:25:25 +0000 Subject: [PATCH 2/7] Add tests --- ...nexistentOffsetInArrayDimFetchRuleTest.php | 10 ++ ...classes-overload-offset-access-invalid.php | 92 +++++++++++++++++++ ...nternal-classes-overload-offset-access.php | 75 +++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php create mode 100644 tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access.php diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index 2838f2cbd9..df22f90d99 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -898,4 +898,14 @@ public function testBug2634(): void $this->analyse([__DIR__ . '/data/bug-2634.php'], []); } + public function testInternalClassesWithOverloadedOffsetAccess(): void + { + $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access.php'], []); + } + + public function testInternalClassesWithOverloadedOffsetAccessInvalid(): void + { + $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php new file mode 100644 index 0000000000..1027b349f2 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php @@ -0,0 +1,92 @@ + Date: Thu, 12 Dec 2024 04:41:17 +0000 Subject: [PATCH 3/7] Split tests for 8.4 and below --- ...nexistentOffsetInArrayDimFetchRuleTest.php | 10 ++ ...s-overload-offset-access-invalid-php84.php | 91 +++++++++++++++++++ ...classes-overload-offset-access-invalid.php | 40 -------- ...l-classes-overload-offset-access-php84.php | 74 +++++++++++++++ ...nternal-classes-overload-offset-access.php | 38 -------- 5 files changed, 175 insertions(+), 78 deletions(-) create mode 100644 tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php create mode 100644 tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-php84.php diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index df22f90d99..3994519ee2 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -903,9 +903,19 @@ public function testInternalClassesWithOverloadedOffsetAccess(): void $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access.php'], []); } + public function testInternalClassesWithOverloadedOffsetAccess84(): void + { + $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-php84.php'], []); + } + public function testInternalClassesWithOverloadedOffsetAccessInvalid(): void { $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid.php'], []); } + public function testInternalClassesWithOverloadedOffsetAccessInvalid84(): void + { + $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid-php84.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php new file mode 100644 index 0000000000..255510033d --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php @@ -0,0 +1,91 @@ += 8.4 +/** + * All of these offset accesses are invalid + * ++ and -- are also disallowed in general are they operate "by ref" + */ +namespace InternalClassesOverloadOffsetAccessInvalid\Php84; + +function test1(\DOMNamedNodeMap $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test2(\Dom\NamedNodeMap $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test3(\DOMNodeList $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test4(\Dom\NodeList $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test5(\Dom\HTMLCollection $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test6(\Dom\DtdNamedNodeMap $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test7(\PDORow $v): void +{ + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); +} + +function test8(\ResourceBundle $v): void +{ + if ($v[0]) { + var_dump($v[0]); + } + $v[] = 'append'; + $v[0] = 'update'; + $v[0] .= ' and again'; + $r1 = &$v[0]; + unset($v[0]); + var_dump($r1); + var_dump($v['name']); + var_dump($v[0]); +} diff --git a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php index 1027b349f2..abc49ce243 100644 --- a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php +++ b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid.php @@ -15,16 +15,6 @@ function test1(\DOMNamedNodeMap $v): void var_dump($r1); } -function test2(\Dom\NamedNodeMap $v): void -{ - $v[] = 'append'; - $v[0] = 'update'; - $v[0] .= ' and again'; - $r1 = &$v[0]; - unset($v[0]); - var_dump($r1); -} - function test3(\DOMNodeList $v): void { $v[] = 'append'; @@ -35,36 +25,6 @@ function test3(\DOMNodeList $v): void var_dump($r1); } -function test4(\Dom\NodeList $v): void -{ - $v[] = 'append'; - $v[0] = 'update'; - $v[0] .= ' and again'; - $r1 = &$v[0]; - unset($v[0]); - var_dump($r1); -} - -function test5(\Dom\HTMLCollection $v): void -{ - $v[] = 'append'; - $v[0] = 'update'; - $v[0] .= ' and again'; - $r1 = &$v[0]; - unset($v[0]); - var_dump($r1); -} - -function test6(\Dom\DtdNamedNodeMap $v): void -{ - $v[] = 'append'; - $v[0] = 'update'; - $v[0] .= ' and again'; - $r1 = &$v[0]; - unset($v[0]); - var_dump($r1); -} - function test7(\PDORow $v): void { $v[] = 'append'; diff --git a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-php84.php b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-php84.php new file mode 100644 index 0000000000..7e1e40e481 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-php84.php @@ -0,0 +1,74 @@ += 8.4 + +namespace InternalClassesOverloadOffsetAccess\Php84; + +function test1(\DOMNamedNodeMap $v): void +{ + if ($v['attribute_name']) { + var_dump($v['attribute_name']); + } + if ($v[0]) { + var_dump($v[0]); + } +} + +function test2(\Dom\NamedNodeMap $v): void +{ + if ($v['attribute_name']) { + var_dump($v['attribute_name']); + } + if ($v[0]) { + var_dump($v[0]); + } +} + +function test3(\DOMNodeList $v): void +{ + if ($v[0]) { + var_dump($v[0]); + } +} + +function test4(\Dom\NodeList $v): void +{ + //var_dump($v['attribute_name']); + if ($v[0]) { + var_dump($v[0]); + } +} + +function test5(\Dom\HTMLCollection $v): void +{ + if ($v['name']) { + var_dump($v['name']); + } + if ($v[0]) { + var_dump($v[0]); + } +} + +function test6(\Dom\DtdNamedNodeMap $v): void +{ + if ($v['name']) { + var_dump($v['name']); + } + if ($v[0]) { + var_dump($v[0]); + } +} + +function test7(\PDORow $v): void +{ + if ($v['name']) { + var_dump($v['name']); + } + if ($v[0]) { + var_dump($v[0]); + } +} + +function test8(\ResourceBundle $v): void +{ + var_dump($v['name']); + var_dump($v[0]); +} diff --git a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access.php b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access.php index 4801970146..6272ee6b9f 100644 --- a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access.php +++ b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access.php @@ -12,16 +12,6 @@ function test1(\DOMNamedNodeMap $v): void } } -function test2(\Dom\NamedNodeMap $v): void -{ - if ($v['attribute_name']) { - var_dump($v['attribute_name']); - } - if ($v[0]) { - var_dump($v[0]); - } -} - function test3(\DOMNodeList $v): void { if ($v[0]) { @@ -29,34 +19,6 @@ function test3(\DOMNodeList $v): void } } -function test4(\Dom\NodeList $v): void -{ - //var_dump($v['attribute_name']); - if ($v[0]) { - var_dump($v[0]); - } -} - -function test5(\Dom\HTMLCollection $v): void -{ - if ($v['name']) { - var_dump($v['name']); - } - if ($v[0]) { - var_dump($v[0]); - } -} - -function test6(\Dom\DtdNamedNodeMap $v): void -{ - if ($v['name']) { - var_dump($v['name']); - } - if ($v[0]) { - var_dump($v[0]); - } -} - function test7(\PDORow $v): void { if ($v['name']) { From 7c60acfc2cab48fe6a1e4ad0aa02b93e12330cd3 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 12 Dec 2024 22:19:15 +0000 Subject: [PATCH 4/7] add version constraints --- .../Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php | 6 ++++++ ...nternal-classes-overload-offset-access-invalid-php84.php | 2 +- .../data/internal-classes-overload-offset-access-php84.php | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index 3994519ee2..4bec61f534 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -905,6 +905,9 @@ public function testInternalClassesWithOverloadedOffsetAccess(): void public function testInternalClassesWithOverloadedOffsetAccess84(): void { + if (version_compare(PHP_VERSION, '8.4.0', '<')) { + $this->markTestSkipped('Test requires PHP version 8.4.'); + } $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-php84.php'], []); } @@ -915,6 +918,9 @@ public function testInternalClassesWithOverloadedOffsetAccessInvalid(): void public function testInternalClassesWithOverloadedOffsetAccessInvalid84(): void { + if (version_compare(PHP_VERSION, '8.4.0', '<')) { + $this->markTestSkipped('Test requires PHP version 8.4.'); + } $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid-php84.php'], []); } diff --git a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php index 255510033d..f57bd14122 100644 --- a/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php +++ b/tests/PHPStan/Rules/Arrays/data/internal-classes-overload-offset-access-invalid-php84.php @@ -1,4 +1,4 @@ -= 8.4 += 8.4 + Date: Sat, 14 Dec 2024 22:19:35 +0000 Subject: [PATCH 5/7] use PHP_VERSION_ID instead --- .../Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index 4bec61f534..d074a66b73 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -905,8 +905,8 @@ public function testInternalClassesWithOverloadedOffsetAccess(): void public function testInternalClassesWithOverloadedOffsetAccess84(): void { - if (version_compare(PHP_VERSION, '8.4.0', '<')) { - $this->markTestSkipped('Test requires PHP version 8.4.'); + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.1.'); } $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-php84.php'], []); } @@ -918,8 +918,8 @@ public function testInternalClassesWithOverloadedOffsetAccessInvalid(): void public function testInternalClassesWithOverloadedOffsetAccessInvalid84(): void { - if (version_compare(PHP_VERSION, '8.4.0', '<')) { - $this->markTestSkipped('Test requires PHP version 8.4.'); + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.1.'); } $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid-php84.php'], []); } From 0669763067844d7b410c26bad75038bda3f8520f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mirtes?= Date: Tue, 17 Dec 2024 09:50:01 +0100 Subject: [PATCH 6/7] Update tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php --- .../Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index d074a66b73..dba451beed 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -906,7 +906,7 @@ public function testInternalClassesWithOverloadedOffsetAccess(): void public function testInternalClassesWithOverloadedOffsetAccess84(): void { if (PHP_VERSION_ID < 80400) { - $this->markTestSkipped('Test requires PHP 8.1.'); + $this->markTestSkipped('Test requires PHP 8.4.'); } $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-php84.php'], []); } From f50ed8600463b97fe9028447587cf9978ff67101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mirtes?= Date: Tue, 17 Dec 2024 09:50:07 +0100 Subject: [PATCH 7/7] Update tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php --- .../Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index dba451beed..6699adb5f7 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -919,7 +919,7 @@ public function testInternalClassesWithOverloadedOffsetAccessInvalid(): void public function testInternalClassesWithOverloadedOffsetAccessInvalid84(): void { if (PHP_VERSION_ID < 80400) { - $this->markTestSkipped('Test requires PHP 8.1.'); + $this->markTestSkipped('Test requires PHP 8.4.'); } $this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid-php84.php'], []); }