diff --git a/tests/PHPStan/Analyser/data/array-destructuring.php b/tests/PHPStan/Analyser/data/array-destructuring.php index abf9bff20c..69e8b03786 100644 --- a/tests/PHPStan/Analyser/data/array-destructuring.php +++ b/tests/PHPStan/Analyser/data/array-destructuring.php @@ -1,5 +1,5 @@ true, 'value' => '123']; diff --git a/tests/PHPStan/Analyser/data/nested-functions.php b/tests/PHPStan/Analyser/data/nested-functions.php index 1d12b75157..b33ed3150a 100644 --- a/tests/PHPStan/Analyser/data/nested-functions.php +++ b/tests/PHPStan/Analyser/data/nested-functions.php @@ -12,8 +12,7 @@ public function doFoo(): self } -function () { - $foo = new Foo(); +function (Foo $foo) { $foo->doFoo() ->doFoo() ->doFoo() diff --git a/tests/PHPStan/Analyser/nsrt/bug-6462.php b/tests/PHPStan/Analyser/nsrt/bug-6462.php index 84c475d48a..51854608d7 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-6462.php +++ b/tests/PHPStan/Analyser/nsrt/bug-6462.php @@ -37,21 +37,19 @@ public function getThis(): self } } -$base = new Base(); -$child = new Child(); -$fixedChild = new FixedChild(); +function (Base $base, Child $child, FixedChild $fixedChild): void { + assertType('Bug6462\Base', $base->getThis()); + assertType('Bug6462\Child', $child->getThis()); -assertType('Bug6462\Base', $base->getThis()); -assertType('Bug6462\Child', $child->getThis()); - -if ($base instanceof \Traversable) { - assertType('Bug6462\Base&Traversable', $base->getThis()); -} + if ($base instanceof \Traversable) { + assertType('Bug6462\Base&Traversable', $base->getThis()); + } -if ($child instanceof \Traversable) { - assertType('Bug6462\Child&Traversable', $child->getThis()); -} + if ($child instanceof \Traversable) { + assertType('Bug6462\Child&Traversable', $child->getThis()); + } -if ($fixedChild instanceof \Traversable) { - assertType('Bug6462\FixedChild&Traversable', $fixedChild->getThis()); -} + if ($fixedChild instanceof \Traversable) { + assertType('Bug6462\FixedChild&Traversable', $fixedChild->getThis()); + } +}; diff --git a/tests/PHPStan/Analyser/nsrt/get-debug-type.php b/tests/PHPStan/Analyser/nsrt/get-debug-type.php index 322c33547f..bc3823a68b 100644 --- a/tests/PHPStan/Analyser/nsrt/get-debug-type.php +++ b/tests/PHPStan/Analyser/nsrt/get-debug-type.php @@ -15,7 +15,7 @@ class D {} * @param int|string $intOrString * @param array|A $arrayOrObject */ -function doFoo(bool $b, int $i, float $f, $d, $r, string $s, array $a, $intOrString, $arrayOrObject) { +function doFoo(bool $b, int $i, float $f, $d, $r, string $s, array $a, $intOrString, $arrayOrObject, \stdClass $std) { $null = null; $resource = fopen('php://memory', 'r'); $o = new \stdClass(); @@ -34,6 +34,7 @@ function doFoo(bool $b, int $i, float $f, $d, $r, string $s, array $a, $intOrStr assertType("'string'", get_debug_type($s)); assertType("'array'", get_debug_type($a)); assertType("string", get_debug_type($o)); + assertType("string", get_debug_type($std)); assertType("'GetDebugType\\\\A'", get_debug_type($A)); assertType("string", get_debug_type($r)); assertType("'bool'|string", get_debug_type($resource)); diff --git a/tests/PHPStan/Analyser/nsrt/instanceof.php b/tests/PHPStan/Analyser/nsrt/instanceof.php index 9ad5cceea7..fe111fb0e4 100644 --- a/tests/PHPStan/Analyser/nsrt/instanceof.php +++ b/tests/PHPStan/Analyser/nsrt/instanceof.php @@ -19,11 +19,10 @@ abstract class BarParent class Foo extends BarParent { - public function someMethod(Expr $foo) + public function someMethod(Expr $foo, Foo $intersected) { $bar = $foo; $baz = doFoo(); - $intersected = new Foo(); $parent = doFoo(); if ($baz instanceof Foo) { diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index 5480eb394c..c2f1edee23 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -96,169 +96,177 @@ public function testImpossibleCheckTypeFunctionCall(): void 'Call to function method_exists() with CheckTypeFunctionCall\Foo and \'doFoo\' will always evaluate to true.', 179, ], + [ + 'Call to function method_exists() with CheckTypeFunctionCall\Foo and \'doFoo\' will always evaluate to true.', + 189, + ], [ 'Call to function method_exists() with $this(CheckTypeFunctionCall\FinalClassWithMethodExists) and \'doFoo\' will always evaluate to true.', - 191, + 201, ], [ 'Call to function method_exists() with $this(CheckTypeFunctionCall\FinalClassWithMethodExists) and \'doBar\' will always evaluate to false.', - 194, + 204, ], [ 'Call to function property_exists() with $this(CheckTypeFunctionCall\FinalClassWithPropertyExists) and \'fooProperty\' will always evaluate to true.', - 210, + 220, ], [ 'Call to function in_array() with arguments int, array{\'foo\', \'bar\'} and true will always evaluate to false.', - 236, + 246, ], [ 'Call to function in_array() with arguments \'bar\'|\'foo\', array{\'baz\', \'lorem\'} and true will always evaluate to false.', - 245, + 255, ], [ 'Call to function in_array() with arguments \'foo\', array{\'foo\'} and true will always evaluate to true.', - 253, + 263, ], [ 'Call to function in_array() with arguments \'foo\', array{\'foo\', \'bar\'} and true will always evaluate to true.', - 257, + 267, ], [ 'Call to function in_array() with arguments \'bar\', array{}|array{\'foo\'} and true will always evaluate to false.', - 321, + 331, ], [ 'Call to function in_array() with arguments \'baz\', array{0: \'bar\', 1?: \'foo\'} and true will always evaluate to false.', - 337, + 347, ], [ 'Call to function in_array() with arguments \'foo\', array{} and true will always evaluate to false.', - 344, + 354, ], [ 'Call to function array_key_exists() with \'a\' and array{a: 1, b?: 2} will always evaluate to true.', - 361, + 371, ], [ 'Call to function array_key_exists() with \'c\' and array{a: 1, b?: 2} will always evaluate to false.', - 367, + 377, ], [ 'Call to function is_string() with mixed will always evaluate to false.', - 561, + 571, ], [ 'Call to function is_callable() with mixed will always evaluate to false.', - 572, + 582, ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExists\' and \'testWithStringFirst…\' will always evaluate to true.', - 586, + 596, ], [ 'Call to function method_exists() with \'UndefinedClass\' and string will always evaluate to false.', - 595, + 605, ], [ 'Call to function method_exists() with \'UndefinedClass\' and \'test\' will always evaluate to false.', - 598, + 608, + ], + [ + 'Call to function method_exists() with CheckTypeFunctionCall\MethodExists and \'testWithNewObjectIn…\' will always evaluate to true.', + 620, ], [ 'Call to function method_exists() with CheckTypeFunctionCall\MethodExists and \'testWithNewObjectIn…\' will always evaluate to true.', - 610, + 635, ], [ 'Call to function method_exists() with $this(CheckTypeFunctionCall\MethodExistsWithTrait) and \'method\' will always evaluate to true.', - 625, + 650, ], [ 'Call to function method_exists() with $this(CheckTypeFunctionCall\MethodExistsWithTrait) and \'someAnother\' will always evaluate to true.', - 628, + 653, ], [ 'Call to function method_exists() with $this(CheckTypeFunctionCall\MethodExistsWithTrait) and \'unknown\' will always evaluate to false.', - 631, + 656, ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.', - 634, + 659, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.', - 637, + 662, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', - 640, + 665, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.', - 643, + 668, ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.', - 646, + 671, ], [ 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', - 649, + 674, ], [ 'Call to function is_string() with string will always evaluate to true.', - 678, + 703, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function assert() with true will always evaluate to true.', - 693, + 718, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function is_numeric() with \'123\' will always evaluate to true.', - 693, + 718, ], [ 'Call to function assert() with false will always evaluate to false.', - 694, + 719, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function is_numeric() with \'blabla\' will always evaluate to false.', - 694, + 719, ], [ 'Call to function assert() with true will always evaluate to true.', - 701, + 726, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to function is_numeric() with 123|float will always evaluate to true.', - 701, + 726, ], [ 'Call to function property_exists() with CheckTypeFunctionCall\Bug2221 and \'foo\' will always evaluate to true.', - 784, + 809, ], [ 'Call to function property_exists() with CheckTypeFunctionCall\Bug2221 and \'foo\' will always evaluate to true.', - 788, + 813, ], [ 'Call to function testIsInt() with int will always evaluate to true.', - 875, + 900, ], [ 'Call to function is_int() with int will always evaluate to true.', - 889, + 914, 'Remove remaining cases below this one and this error will disappear too.', ], [ 'Call to function in_array() with arguments 1, array and true will always evaluate to false.', - 927, + 952, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], ], diff --git a/tests/PHPStan/Rules/Comparison/data/check-type-function-call.php b/tests/PHPStan/Rules/Comparison/data/check-type-function-call.php index 814d93ae60..e84f4f0901 100644 --- a/tests/PHPStan/Rules/Comparison/data/check-type-function-call.php +++ b/tests/PHPStan/Rules/Comparison/data/check-type-function-call.php @@ -181,6 +181,16 @@ public function doFoo() } } + public function doBar(Foo $foo) + { + if (method_exists($foo, 'test')) { + + } + if (method_exists($foo, 'doFoo')) { + + } + } + } final class FinalClassWithMethodExists @@ -616,6 +626,21 @@ public function testWithNewObjectInFirstArgument(): void if (method_exists((new MethodExists()), $string)) { } } + + public function testWithTypehintedObject(MethodExists $methodExists): void + { + /** @var string $string */ + $string = doFoo(); + + if (method_exists($methodExists, 'testWithNewObjectInFirstArgument')) { + } + + if (method_exists($methodExists, 'undefinedMethod')) { + } + + if (method_exists($methodExists, $string)) { + } + } } trait MethodExistsTrait diff --git a/tests/PHPStan/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRuleTest.php b/tests/PHPStan/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRuleTest.php index 67f6f42b4e..8300080801 100644 --- a/tests/PHPStan/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/CallToMethodStatementWithoutImpurePointsRuleTest.php @@ -48,13 +48,17 @@ public function testRule(): void 'Call to method CallToMethodWithoutImpurePoints\y::myFinalBaseFunc() on a separate line has no effect.', 41, ], + [ + 'Call to method CallToMethodWithoutImpurePoints\y::myFinalBaseFunc() on a separate line has no effect.', + 62, + ], [ 'Call to method CallToMethodWithoutImpurePoints\AbstractFoo::myFunc() on a separate line has no effect.', - 119, + 140, ], [ 'Call to method CallToMethodWithoutImpurePoints\CallsPrivateMethodWithoutImpurePoints::doBar() on a separate line has no effect.', - 127, + 148, ], ]); } diff --git a/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php b/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php index e9f82b1476..e22db7862e 100644 --- a/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php +++ b/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php @@ -41,6 +41,27 @@ function (): void { $subSubY->myFinalBaseFunc(); }; +function (y $xy, finalX $finalX): void { + $xy = new y(); + if (rand(0,1)) { + $xy = $finalX; + } + $xy->myFunc(); +}; + +function (Y $xy, finalX $finalX): void { + // case-insensitive class name + if (rand(0,1)) { + $xy = $finalX; + } + $xy->myFunc(); +}; + +function (subY $subY): void { + $subY->myFunc(); + $subY->myFinalBaseFunc(); +}; + class y { function myFunc() diff --git a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php index 6eacf1535d..adcf6472a6 100644 --- a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php @@ -363,11 +363,11 @@ public function testBug4852(): void $this->analyse([__DIR__ . '/data/bug-4852.php'], [ [ 'Dead catch - Exception is never thrown in the try block.', - 70, + 78, ], [ 'Dead catch - Exception is never thrown in the try block.', - 77, + 85, ], ]); } diff --git a/tests/PHPStan/Rules/Exceptions/data/bug-4852.php b/tests/PHPStan/Rules/Exceptions/data/bug-4852.php index 058f6c1a1f..dfc01e41c8 100644 --- a/tests/PHPStan/Rules/Exceptions/data/bug-4852.php +++ b/tests/PHPStan/Rules/Exceptions/data/bug-4852.php @@ -61,9 +61,17 @@ public function offsetUnset ($offset) {} try { $buz[] = 'value'; } catch (Exception $e) { - // not dead + // dead because $buz cannot be a subclass } +function (MaybeThrows2 $buz): void { + try { + $buz[] = 'value'; + } catch (Exception $e) { + // not dead + } +}; + $baz = new DefinitelyNoThrows(); try { $baz[] = 'value'; diff --git a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php index a8ffcaf800..cde66da1c8 100644 --- a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php @@ -106,48 +106,52 @@ public function testRule(): void 'Trying to invoke CallCallables\Baz but it might not be a callable.', 113, ], + [ + 'Trying to invoke CallCallables\Baz but it might not be a callable.', + 122, + ], [ 'Trying to invoke array{object, \'bar\'} but it might not be a callable.', - 131, + 140, ], [ 'Closure invoked with 0 parameters, 3 required.', - 146, + 155, ], [ 'Closure invoked with 1 parameter, 3 required.', - 147, + 156, ], [ 'Closure invoked with 2 parameters, 3 required.', - 148, + 157, ], [ 'Trying to invoke array{object, \'yo\'} but it might not be a callable.', - 163, + 172, ], [ 'Trying to invoke array{object, \'yo\'} but it might not be a callable.', - 167, + 176, ], [ 'Trying to invoke array{\'CallCallables\\\\CallableInForeach\', \'bar\'|\'foo\'} but it might not be a callable.', - 179, + 188, ], [ 'Trying to invoke array{\'CallCallables\\\\ConstantArrayUnionCallables\'|\'DateTimeImmutable\', \'doFoo\'} but it might not be a callable.', - 205, + 214, ], [ 'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\', \'doBaz\'|\'doFoo\'} but it might not be a callable.', - 212, + 221, ], ]; if (PHP_VERSION_ID >= 80000) { $errors[] = [ 'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\'|\'CallCallables\\\ConstantArrayUnionCallablesTest\', \'doBar\'|\'doFoo\'} but it\'s not a callable.', - 220, + 229, ]; } diff --git a/tests/PHPStan/Rules/Functions/data/callables.php b/tests/PHPStan/Rules/Functions/data/callables.php index e2364e5aa5..def053f902 100644 --- a/tests/PHPStan/Rules/Functions/data/callables.php +++ b/tests/PHPStan/Rules/Functions/data/callables.php @@ -117,6 +117,15 @@ public function doBar() } } + public function doBaz(Baz $baz) + { + $baz(); + + if (method_exists($baz, '__invoke')) { + $baz(); + } + } + } class MethodExistsCheckFirst diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index b82eb1596f..bedf530cdc 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -3054,82 +3054,87 @@ public function testObjectShapes(): void 14, 'Exception might not have property $foo.', ], + [ + 'Parameter #1 $o of method ObjectShapesAcceptance\Foo::doBar() expects object{foo: int, bar: string}, Exception given.', + 15, + 'Exception might not have property $foo.', + ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Foo::doBar() expects object{foo: int, bar: string}, object{foo: string, bar: int} given.', - 36, + 37, 'Property ($foo) type int does not accept type string.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Foo::doBar() expects object{foo: int, bar: string}, object{foo?: int, bar: string} given.', - 37, + 38, 'object{foo?: int, bar: string} might not have property $foo.', ], [ 'Parameter #1 $std of method ObjectShapesAcceptance\Foo::requireStdClass() expects stdClass, object{foo: string, bar: int} given.', - 40, + 41, ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Foo::doBar() expects object{foo: int, bar: string}, object{foo: string, bar: int}&stdClass given.', - 43, + 44, 'Property ($foo) type int does not accept type string.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Foo::doBar() expects object{foo: int, bar: string}, object given.', - 54, + 55, '• object might not have property $foo. • object might not have property $bar.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Foo::doBar() expects object{foo: int, bar: string}, stdClass given.', - 55, + 56, ], [ 'Parameter #1 $bar of method ObjectShapesAcceptance\Bar::requireBar() expects ObjectShapesAcceptance\Bar, object{a: int} given.', - 71, + 72, ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Bar::doBar() expects object{a: string}, ObjectShapesAcceptance\Bar given.', - 77, + 78, 'Property ($a) type string does not accept type int.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Baz::doBar() expects object{a: int}, $this(ObjectShapesAcceptance\Baz) given.', - 105, + 106, 'Property ObjectShapesAcceptance\Baz::$a is not public.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Baz::doBaz() expects object{b: int}, $this(ObjectShapesAcceptance\Baz) given.', - 106, + 107, 'Property ObjectShapesAcceptance\Baz::$b is static.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Baz::doLorem() expects object{c: int}, $this(ObjectShapesAcceptance\Baz) given.', - 107, + 108, 'Property ObjectShapesAcceptance\Baz::$c is not readable.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\Baz::doIpsum() expects object{d: array{foo: string}}, $this(ObjectShapesAcceptance\Baz) given.', - 108, + 109, 'Property ($d) type array{foo: string} does not accept type array{foo: int}: Offset \'foo\' (string) does not accept type int.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\OptionalProperty::doBar() expects object{foo?: int}, object{foo?: string} given.', - 156, + 157, 'Property ($foo) type int does not accept type string.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\OptionalProperty::doBaz() expects object{foo: int}, object{foo?: string} given.', - 157, + 158, 'Property ($foo) type int does not accept type string.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\TestAcceptance::doFoo() expects object{foo: int}, Traversable given.', - 209, + 210, 'Traversable might not have property $foo.', ], [ 'Parameter #1 $o of method ObjectShapesAcceptance\TestAcceptance::doFoo() expects object{foo: int}, ObjectShapesAcceptance\FinalClass given.', - 210, + 211, PHP_VERSION_ID < 80200 ? 'ObjectShapesAcceptance\FinalClass might not have property $foo.' : 'ObjectShapesAcceptance\FinalClass does not have property $foo.', ], ]); diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 8de2c7a5d9..0c658ce936 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -242,43 +242,43 @@ public function testReturnTypeRule(): void ], [ 'Method ReturnTypes\AssertThisInstanceOf::doBar() should return $this(ReturnTypes\AssertThisInstanceOf) but returns ReturnTypes\AssertThisInstanceOf&ReturnTypes\FooInterface.', - 840, + 839, ], [ 'Method ReturnTypes\NestedArrayCheck::doFoo() should return array but returns array>.', - 860, + 859, ], [ 'Method ReturnTypes\NestedArrayCheck::doBar() should return array but returns array>.', - 875, + 874, ], [ 'Method ReturnTypes\Foo2::returnIntFromParent() should return int but returns string.', - 950, + 949, ], [ 'Method ReturnTypes\Foo2::returnIntFromParent() should return int but returns ReturnTypes\integer.', - 953, + 952, ], [ 'Method ReturnTypes\VariableOverwrittenInForeach::doFoo() should return int but returns int|string.', - 1011, + 1010, ], [ 'Method ReturnTypes\VariableOverwrittenInForeach::doBar() should return int but returns int|string.', - 1026, + 1025, ], [ 'Method ReturnTypes\ReturnStaticGeneric::instanceReturnsStatic() should return static(ReturnTypes\ReturnStaticGeneric) but returns ReturnTypes\ReturnStaticGeneric.', - 1066, + 1065, ], [ 'Method ReturnTypes\NeverReturn::doFoo() should never return but return statement found.', - 1241, + 1240, ], [ 'Method ReturnTypes\NeverReturn::doBaz3() should never return but return statement found.', - 1254, + 1253, ], ]); } diff --git a/tests/PHPStan/Rules/Methods/data/object-shapes.php b/tests/PHPStan/Rules/Methods/data/object-shapes.php index 248eeecc30..8df09d5f93 100644 --- a/tests/PHPStan/Rules/Methods/data/object-shapes.php +++ b/tests/PHPStan/Rules/Methods/data/object-shapes.php @@ -8,10 +8,11 @@ class Foo { - public function doFoo(): void + public function doFoo(Exception $e): void { $this->doBar(new stdClass()); $this->doBar(new Exception()); + $this->doBar($e); } /** diff --git a/tests/PHPStan/Rules/Methods/data/returnTypes.php b/tests/PHPStan/Rules/Methods/data/returnTypes.php index b1c453648a..e7030f8ad8 100644 --- a/tests/PHPStan/Rules/Methods/data/returnTypes.php +++ b/tests/PHPStan/Rules/Methods/data/returnTypes.php @@ -833,9 +833,8 @@ public function doFoo() /** * @return $this */ - public function doBar() + public function doBar(self $otherInstance) { - $otherInstance = new self(); assert($otherInstance instanceof FooInterface); return $otherInstance; } diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php index 1b79507bad..57d68802f9 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php @@ -634,7 +634,7 @@ public function dataDynamicProperties(): array $errors = [ [ 'Access to an undefined property DynamicProperties\Baz::$dynamicProperty.', - 23, + 29, $tipText, ], ]; @@ -670,22 +670,37 @@ public function dataDynamicProperties(): array 16, $tipText, ], + [ + 'Access to an undefined property DynamicProperties\Bar::$dynamicProperty.', + 20, + $tipText, + ], + [ + 'Access to an undefined property DynamicProperties\Bar::$dynamicProperty.', + 21, + $tipText, + ], + [ + 'Access to an undefined property DynamicProperties\Bar::$dynamicProperty.', + 22, + $tipText, + ], ], $errors); $errorsWithMore = array_merge($errorsWithMore, [ [ 'Access to an undefined property DynamicProperties\Baz::$dynamicProperty.', - 26, + 32, $tipText, ], [ 'Access to an undefined property DynamicProperties\Baz::$dynamicProperty.', - 27, + 33, $tipText, ], [ 'Access to an undefined property DynamicProperties\Baz::$dynamicProperty.', - 28, + 34, $tipText, ], ]); @@ -693,32 +708,32 @@ public function dataDynamicProperties(): array $otherErrors = [ [ 'Access to an undefined property DynamicProperties\FinalFoo::$dynamicProperty.', - 36, + 42, $tipText, ], [ 'Access to an undefined property DynamicProperties\FinalFoo::$dynamicProperty.', - 37, + 43, $tipText, ], [ 'Access to an undefined property DynamicProperties\FinalFoo::$dynamicProperty.', - 38, + 44, $tipText, ], [ 'Access to an undefined property DynamicProperties\FinalBar::$dynamicProperty.', - 41, + 47, $tipText, ], [ 'Access to an undefined property DynamicProperties\FinalBar::$dynamicProperty.', - 42, + 48, $tipText, ], [ 'Access to an undefined property DynamicProperties\FinalBar::$dynamicProperty.', - 43, + 49, $tipText, ], ]; @@ -727,7 +742,7 @@ public function dataDynamicProperties(): array [false, PHP_VERSION_ID < 80200 ? [ [ 'Access to an undefined property DynamicProperties\Baz::$dynamicProperty.', - 23, + 29, $tipText, ], ] : array_merge($errors, $otherErrors)], @@ -799,10 +814,15 @@ public function testPhp82AndDynamicProperties(bool $b): void 71, $tipText, ]; + $errors[] = [ + 'Access to an undefined property Php82DynamicProperties\HelloWorld::$world.', + 78, + $tipText, + ]; } $errors[] = [ 'Access to an undefined property Php82DynamicProperties\FinalHelloWorld::$world.', - 105, + 112, $tipText, ]; } elseif ($b) { @@ -811,9 +831,14 @@ public function testPhp82AndDynamicProperties(bool $b): void 71, $tipText, ]; + $errors[] = [ + 'Access to an undefined property Php82DynamicProperties\HelloWorld::$world.', + 78, + $tipText, + ]; $errors[] = [ 'Access to an undefined property Php82DynamicProperties\FinalHelloWorld::$world.', - 105, + 112, $tipText, ]; } diff --git a/tests/PHPStan/Rules/Properties/data/dynamic-properties.php b/tests/PHPStan/Rules/Properties/data/dynamic-properties.php index 055029152e..d354c028ea 100644 --- a/tests/PHPStan/Rules/Properties/data/dynamic-properties.php +++ b/tests/PHPStan/Rules/Properties/data/dynamic-properties.php @@ -15,6 +15,12 @@ public function doBar() { empty($bar->dynamicProperty); $bar->dynamicProperty ?? 'test'; } + + public function doBaz(Bar $bar) { + isset($bar->dynamicProperty); + empty($bar->dynamicProperty); + $bar->dynamicProperty ?? 'test'; + } } #[\AllowDynamicProperties] diff --git a/tests/PHPStan/Rules/Properties/data/php-82-dynamic-properties.php b/tests/PHPStan/Rules/Properties/data/php-82-dynamic-properties.php index 92e14eaba2..44bd919027 100644 --- a/tests/PHPStan/Rules/Properties/data/php-82-dynamic-properties.php +++ b/tests/PHPStan/Rules/Properties/data/php-82-dynamic-properties.php @@ -74,6 +74,13 @@ function (): void { } }; +function (HelloWorld $hello): void { + if(isset($hello->world)) + { + echo $hello->world; + } +}; + final class FinalHelloWorld { public function __get(string $attribute): mixed diff --git a/tests/PHPStan/Rules/Variables/UnsetRuleTest.php b/tests/PHPStan/Rules/Variables/UnsetRuleTest.php index 0564fbe509..8f7081b679 100644 --- a/tests/PHPStan/Rules/Variables/UnsetRuleTest.php +++ b/tests/PHPStan/Rules/Variables/UnsetRuleTest.php @@ -115,34 +115,38 @@ public function testBug12421(): void if (PHP_VERSION_ID >= 80400) { $errors[] = [ 'Cannot unset property Bug12421\RegularProperty::$y because it might have hooks in a subclass.', - 7, + 6, + ]; + $errors[] = [ + 'Cannot unset property Bug12421\RegularProperty::$y because it might have hooks in a subclass.', + 9, ]; } $errors = array_merge($errors, [ [ 'Cannot unset readonly Bug12421\NativeReadonlyClass::$y property.', - 11, + 13, ], [ 'Cannot unset readonly Bug12421\NativeReadonlyProperty::$y property.', - 15, + 17, ], [ 'Cannot unset @readonly Bug12421\PhpdocReadonlyClass::$y property.', - 19, + 21, ], [ 'Cannot unset @readonly Bug12421\PhpdocReadonlyProperty::$y property.', - 23, + 25, ], [ 'Cannot unset @readonly Bug12421\PhpdocImmutableClass::$y property.', - 27, + 29, ], [ 'Cannot unset readonly Bug12421\NativeReadonlyProperty::$y property.', - 34, + 36, ], ]); diff --git a/tests/PHPStan/Rules/Variables/data/bug-12421.php b/tests/PHPStan/Rules/Variables/data/bug-12421.php index eb0c53f755..9ed7c9b217 100644 --- a/tests/PHPStan/Rules/Variables/data/bug-12421.php +++ b/tests/PHPStan/Rules/Variables/data/bug-12421.php @@ -2,8 +2,10 @@ namespace Bug12421; -function doFoo() { - $x = new RegularProperty(); +function doFoo(RegularProperty $x) { + unset($x->y); + var_dump($x->y); + unset($x->y); var_dump($x->y);