diff --git a/composer.json b/composer.json index e73f0ddf0f..66c8349458 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "nette/utils": "^3.1.3", "nikic/php-parser": "4.13.1", "ondram/ci-detector": "^3.4.0", - "ondrejmirtes/better-reflection": "4.3.79", + "ondrejmirtes/better-reflection": "4.3.80", "phpstan/php-8-stubs": "^0.1.23", "phpstan/phpdoc-parser": "^1.2.0", "react/child-process": "^0.6.4", diff --git a/composer.lock b/composer.lock index 05e3cfc55e..4dc0bce021 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f02e0a2bf75a18142c2b237f5b10272c", + "content-hash": "6155dc11ecc4374c1dda15c039fdf1ae", "packages": [ { "name": "clue/block-react", @@ -2074,16 +2074,16 @@ }, { "name": "ondrejmirtes/better-reflection", - "version": "4.3.79", + "version": "4.3.80", "source": { "type": "git", "url": "https://github.com/ondrejmirtes/BetterReflection.git", - "reference": "fffbbc5d6d9bbb03d26af11b153847e561c4d1cb" + "reference": "56f215f08c4421f69e2d0e82096601b0b4fbaa2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/fffbbc5d6d9bbb03d26af11b153847e561c4d1cb", - "reference": "fffbbc5d6d9bbb03d26af11b153847e561c4d1cb", + "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/56f215f08c4421f69e2d0e82096601b0b4fbaa2c", + "reference": "56f215f08c4421f69e2d0e82096601b0b4fbaa2c", "shasum": "" }, "require": { @@ -2138,9 +2138,9 @@ ], "description": "Better Reflection - an improved code reflection API", "support": { - "source": "https://github.com/ondrejmirtes/BetterReflection/tree/4.3.79" + "source": "https://github.com/ondrejmirtes/BetterReflection/tree/4.3.80" }, - "time": "2021-11-09T09:09:38+00:00" + "time": "2021-11-11T09:24:16+00:00" }, { "name": "phpstan/php-8-stubs", diff --git a/src/Type/ConstantTypeHelper.php b/src/Type/ConstantTypeHelper.php index 837a7f5f26..dbf53d5a3c 100644 --- a/src/Type/ConstantTypeHelper.php +++ b/src/Type/ConstantTypeHelper.php @@ -39,6 +39,8 @@ public static function getTypeFromValue($value): Type $arrayBuilder->setOffsetValueType(self::getTypeFromValue($k), self::getTypeFromValue($v)); } return $arrayBuilder->getArray(); + } elseif (is_object($value)) { + return new ObjectType(get_class($value)); } return new MixedType(); diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 962886fce5..a689d4d187 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -542,6 +542,15 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2760.php'); + if (PHP_VERSION_ID >= 80100 || self::$useStaticReflectionProvider) { + yield from $this->gatherAssertTypes(__DIR__ . '/data/new-in-initializers.php'); + + if (PHP_VERSION_ID >= 80100) { + define('TEST_OBJECT_CONSTANT', new \stdClass()); + yield from $this->gatherAssertTypes(__DIR__ . '/data/new-in-initializers-runtime.php'); + } + } + yield from $this->gatherAssertTypes(__DIR__ . '/data/filesystem-functions.php'); } diff --git a/tests/PHPStan/Analyser/data/new-in-initializers-runtime.php b/tests/PHPStan/Analyser/data/new-in-initializers-runtime.php new file mode 100644 index 0000000000..4fc08b50be --- /dev/null +++ b/tests/PHPStan/Analyser/data/new-in-initializers-runtime.php @@ -0,0 +1,7 @@ += 8.1 + +namespace NewInInitializers; + +use function PHPStan\Testing\assertType; + +assertType('stdClass', TEST_OBJECT_CONSTANT); diff --git a/tests/PHPStan/Analyser/data/new-in-initializers.php b/tests/PHPStan/Analyser/data/new-in-initializers.php new file mode 100644 index 0000000000..091e0ee628 --- /dev/null +++ b/tests/PHPStan/Analyser/data/new-in-initializers.php @@ -0,0 +1,46 @@ += 8.1 + +namespace NewInInitializers; + +use function PHPStan\Testing\assertType; + +class Foo +{ + + /** + * @template T of object + * @param T $test + * @return T + */ + public function doFoo( + object $test = new \stdClass() + ): object + { + return $test; + } + + #[\Test(new \stdClass())] + public function doBar() + { + assertType(\stdClass::class, $this->doFoo()); + assertType('$this(NewInInitializers\Foo)', $this->doFoo($this)); + assertType(Bar::class, $this->doFoo(new Bar())); + } + +} + +class Bar extends Foo +{ + + public function doBar() + { + + } + + public function doBaz() + { + static $o = new \stdClass(); + assertType('mixed', $o); + } + +} diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php index c28ab59464..0985d31595 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocatorTest.php @@ -114,6 +114,10 @@ public function dataConst(): array 'const_with_dir_const', str_replace('\\', '/', __DIR__ . '/data'), ], + [ + 'OPTIMIZED_SFSL_OBJECT_CONSTANT', + new \stdClass(), + ], ]; } @@ -130,7 +134,7 @@ public function testConst(string $constantName, $value): void $constantReflector = new ConstantReflector($locator, $classReflector); $constant = $constantReflector->reflect($constantName); $this->assertSame($constantName, $constant->getName()); - $this->assertSame($value, $constant->getValue()); + $this->assertEquals($value, $constant->getValue()); } public function dataConstUnknown(): array diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/const.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/const.php index eba1d99941..ce333cbfb7 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/const.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/const.php @@ -10,3 +10,5 @@ define('TEST_VARIABLE', $foo); define('const_with_dir_const', __DIR__); + +define('OPTIMIZED_SFSL_OBJECT_CONSTANT', new \stdClass()); diff --git a/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php b/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php index cf9640685c..6c4dfc45a6 100644 --- a/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php @@ -45,4 +45,18 @@ public function testBug2573(): void $this->analyse([__DIR__ . '/data/bug-2573.php'], []); } + public function testNewInInitializers(): void + { + if (PHP_VERSION_ID < 80100 && !self::$useStaticReflectionProvider) { + $this->markTestSkipped('Test requires PHP 8.0.'); + } + + $this->analyse([__DIR__ . '/data/new-in-initializers.php'], [ + [ + 'Default value of the parameter #1 $i (stdClass) of method MethodNewInInitializers\Foo::doFoo() is incompatible with type int.', + 11, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/new-in-initializers.php b/tests/PHPStan/Rules/Methods/data/new-in-initializers.php new file mode 100644 index 0000000000..5369835557 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/new-in-initializers.php @@ -0,0 +1,16 @@ += 8.1 + +namespace MethodNewInInitializers; + +class Foo +{ + + /** + * @param int $i + */ + public function doFoo($i = new \stdClass(), object $o = new \stdClass()) + { + + } + +}