diff --git a/src/Type/IntersectionType.php b/src/Type/IntersectionType.php index a678616cc4..2d305b6883 100644 --- a/src/Type/IntersectionType.php +++ b/src/Type/IntersectionType.php @@ -368,6 +368,7 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes) if ( ($type instanceof AccessoryLowercaseStringType || $type instanceof AccessoryUppercaseStringType) && !$level->isPrecise() + && !$level->isCache() ) { continue; } diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index 33069e9377..f459041746 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -337,7 +337,7 @@ public function describe(VerbosityLevel $level): string } } - if ($level->isPrecise()) { + if ($level->isPrecise() || $level->isCache()) { $duplicates = array_diff_assoc($typeNames, array_unique($typeNames)); if (count($duplicates) > 0) { $indexByDuplicate = array_fill_keys($duplicates, 0); diff --git a/src/Type/VerbosityLevel.php b/src/Type/VerbosityLevel.php index 12b5ecbd15..59259d2df7 100644 --- a/src/Type/VerbosityLevel.php +++ b/src/Type/VerbosityLevel.php @@ -86,6 +86,11 @@ public function isPrecise(): bool return $this->value === self::PRECISE; } + public function isCache(): bool + { + return $this->value === self::CACHE; + } + /** @api */ public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acceptedType = null): self { diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index ac15221d6b..5da8bfa7b0 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -1244,6 +1244,11 @@ public function testBug13043(): void $this->analyse([__DIR__ . '/data/bug-13043.php'], []); } + public function testBug12739(): void + { + $this->analyse([__DIR__ . '/data/bug-12739.php'], []); + } + public function testBug12928(): void { $this->analyse([__DIR__ . '/data/bug-12928.php'], [ diff --git a/tests/PHPStan/Rules/Methods/data/bug-12739.php b/tests/PHPStan/Rules/Methods/data/bug-12739.php new file mode 100644 index 0000000000..646910cf3e --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-12739.php @@ -0,0 +1,58 @@ +> + */ + abstract public static function getClassIdentify() : string; +} + +/** + * @extends ScalarType + */ +class MyInt extends ScalarType { + public static function getClassIdentify() : string { + return MyInt::class; + } +} + +/** + * @extends ScalarType + */ +class MyString extends ScalarType { + public static function getClassIdentify() : string { + return MyString::class; + } +} + +/** + * @extends ScalarType + */ +class MyLowerString extends ScalarType { + public static function getClassIdentify() : string { + return MyLowerString::class; + } +} + +/** + * @extends ScalarType + */ +class MyUpperString extends ScalarType { + public static function getClassIdentify() : string { + return MyUpperString::class; + } +} + +/** + * @extends ScalarType + */ +class MyClassString extends ScalarType { + public static function getClassIdentify() : string { + return MyClassString::class; + } +} diff --git a/tests/PHPStan/Type/UnionTypeTest.php b/tests/PHPStan/Type/UnionTypeTest.php index 1212e5b08a..c93a5e8d47 100644 --- a/tests/PHPStan/Type/UnionTypeTest.php +++ b/tests/PHPStan/Type/UnionTypeTest.php @@ -708,12 +708,14 @@ public static function dataDescribe(): array 'int|string', 'int|string', 'int|string', + 'int|string', ], [ new UnionType([new IntegerType(), new StringType(), new NullType()]), 'int|string|null', 'int|string|null', 'int|string|null', + 'int|string|null', ], [ new UnionType([ @@ -733,6 +735,7 @@ public static function dataDescribe(): array new ConstantStringType('2'), new ConstantStringType('1'), ]), + "1|2|2.2|10|'1'|'10'|'10aaa'|'11aaa'|'1aaa'|'2'|'2aaa'|'foo'|stdClass-PHPStan\Type\ObjectType-|true|null", "1|2|2.2|10|'1'|'10'|'10aaa'|'11aaa'|'1aaa'|'2'|'2aaa'|'foo'|stdClass|true|null", "1|2|2.2|10|'1'|'10'|'10aaa'|'11aaa'|'1aaa'|'2'|'2aaa'|'foo'|stdClass|true|null", 'float|int|stdClass|string|true|null', @@ -757,6 +760,7 @@ public static function dataDescribe(): array ), '\'aaa\'|array{a: int, b: float}|array{a: string, b: bool}', '\'aaa\'|array{a: int, b: float}|array{a: string, b: bool}', + '\'aaa\'|array{a: int, b: float}|array{a: string, b: bool}', 'array|string', ], [ @@ -779,6 +783,7 @@ public static function dataDescribe(): array ), '\'aaa\'|array{a: string, b: bool}|array{b: int, c: float}', '\'aaa\'|array{a: string, b: bool}|array{b: int, c: float}', + '\'aaa\'|array{a: string, b: bool}|array{b: int, c: float}', 'array|string', ], [ @@ -801,6 +806,7 @@ public static function dataDescribe(): array ), '\'aaa\'|array{a: string, b: bool}|array{c: int, d: float}', '\'aaa\'|array{a: string, b: bool}|array{c: int, d: float}', + '\'aaa\'|array{a: string, b: bool}|array{c: int, d: float}', 'array|string', ], [ @@ -822,6 +828,7 @@ public static function dataDescribe(): array ), 'array{int, bool, float}|array{string}', 'array{int, bool, float}|array{string}', + 'array{int, bool, float}|array{string}', 'array', ], [ @@ -835,6 +842,7 @@ public static function dataDescribe(): array ), 'array{}|array{foooo: \'barrr\'}', 'array{}|array{foooo: \'barrr\'}', + 'array{}|array{foooo: \'barrr\'}', 'array', ], [ @@ -847,6 +855,7 @@ public static function dataDescribe(): array ), 'int|numeric-string', 'int|numeric-string', + 'int|numeric-string', 'int|string', ], [ @@ -857,6 +866,7 @@ public static function dataDescribe(): array 'int<0, 4>|int<6, 10>', 'int<0, 4>|int<6, 10>', 'int<0, 4>|int<6, 10>', + 'int<0, 4>|int<6, 10>', ], [ TypeCombinator::union( @@ -869,6 +879,7 @@ public static function dataDescribe(): array new NullType(), ), 'TFoo of int (class foo, parameter)|null', + 'TFoo of int (class foo, parameter)|null', '(TFoo of int)|null', '(TFoo of int)|null', ], @@ -882,6 +893,7 @@ public static function dataDescribe(): array ), new GenericClassStringType(new ObjectType('Abc')), ), + 'class-string|TFoo of int (class foo, parameter)', 'class-string|TFoo of int (class foo, parameter)', 'class-string|TFoo of int', 'class-string|TFoo of int', @@ -897,6 +909,7 @@ public static function dataDescribe(): array new NullType(), ), 'TFoo (class foo, parameter)|null', + 'TFoo (class foo, parameter)|null', 'TFoo|null', 'TFoo|null', ], @@ -916,11 +929,13 @@ public static function dataDescribe(): array new NullType(), ), 'TFoo of TBar (class foo, parameter) (class foo, parameter)|null', + 'TFoo of TBar (class foo, parameter) (class foo, parameter)|null', '(TFoo of TBar)|null', '(TFoo of TBar)|null', ], [ new UnionType([new ObjectType('Foo'), new ObjectType('Foo')]), + 'Foo-PHPStan\Type\ObjectType-#1|Foo-PHPStan\Type\ObjectType-#2', 'Foo#1|Foo#2', 'Foo', 'Foo', @@ -931,11 +946,13 @@ public static function dataDescribe(): array #[DataProvider('dataDescribe')] public function testDescribe( Type $type, + string $expectedCacheDescription, string $expectedPreciseDescription, string $expectedValueDescription, string $expectedTypeOnlyDescription, ): void { + $this->assertSame($expectedCacheDescription, $type->describe(VerbosityLevel::cache())); $this->assertSame($expectedPreciseDescription, $type->describe(VerbosityLevel::precise())); $this->assertSame($expectedValueDescription, $type->describe(VerbosityLevel::value())); $this->assertSame($expectedTypeOnlyDescription, $type->describe(VerbosityLevel::typeOnly()));