From 01d608d945a975cb030cef0711490589c847e0cf Mon Sep 17 00:00:00 2001 From: VincentLanglet <9052536+VincentLanglet@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:06:16 +0000 Subject: [PATCH 1/4] Fix class-string constants described as 'string' at typeOnly verbosity - ConstantStringType::describe() at typeOnly level now returns 'class-string' instead of 'string' when the constant is a known class-string - This fixes misleading error messages like "returns string" when the actual type is a class-string (e.g. from SomeClass::class expressions) - Updated test expectations in 5 test files to reflect improved error messages - Added regression test for phpstan/phpstan#14440 --- src/Type/Constant/ConstantStringType.php | 2 +- .../CallToFunctionParametersRuleTest.php | 22 +++++++------- .../Rules/Methods/CallMethodsRuleTest.php | 4 +-- .../Methods/CallStaticMethodsRuleTest.php | 2 +- .../Rules/Methods/ReturnTypeRuleTest.php | 16 +++++++++- .../PHPStan/Rules/Methods/data/bug-14440.php | 29 +++++++++++++++++++ 6 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 tests/PHPStan/Rules/Methods/data/bug-14440.php diff --git a/src/Type/Constant/ConstantStringType.php b/src/Type/Constant/ConstantStringType.php index 40d0773c48d..3497cdbfc3f 100644 --- a/src/Type/Constant/ConstantStringType.php +++ b/src/Type/Constant/ConstantStringType.php @@ -113,7 +113,7 @@ public function getObjectTypeOrClassStringObjectType(): Type public function describe(VerbosityLevel $level): string { return $level->handle( - static fn (): string => 'string', + fn (): string => $this->isClassString ? 'class-string<' . $this->value . '>' : 'string', function (): string { $value = $this->value; diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 60b40422305..406194352b0 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -1161,7 +1161,7 @@ public function testBug4413(): void require_once __DIR__ . '/data/bug-4413.php'; $this->analyse([__DIR__ . '/data/bug-4413.php'], [ [ - 'Parameter #1 $date of function Bug4413\takesDate expects class-string, string given.', + 'Parameter #1 $date of function Bug4413\takesDate expects class-string, class-string given.', 18, ], ]); @@ -1200,11 +1200,11 @@ public function testBug4371(): void { $errors = [ [ - 'Parameter #1 $object_or_class of function is_a expects object, string given.', + 'Parameter #1 $object_or_class of function is_a expects object, class-string given.', 14, ], [ - 'Parameter #1 $object_or_class of function is_a expects object, string given.', + 'Parameter #1 $object_or_class of function is_a expects object, class-string given.', 22, ], ]; @@ -1213,11 +1213,11 @@ public function testBug4371(): void // php 7.x had different parameter names $errors = [ [ - 'Parameter #1 $object_or_string of function is_a expects object, string given.', + 'Parameter #1 $object_or_string of function is_a expects object, class-string given.', 14, ], [ - 'Parameter #1 $object_or_string of function is_a expects object, string given.', + 'Parameter #1 $object_or_string of function is_a expects object, class-string given.', 22, ], ]; @@ -1230,15 +1230,15 @@ public function testIsSubclassAllowString(): void { $errors = [ [ - 'Parameter #1 $object_or_class of function is_subclass_of expects object, string given.', + 'Parameter #1 $object_or_class of function is_subclass_of expects object, class-string given.', 11, ], [ - 'Parameter #1 $object_or_class of function is_subclass_of expects object, string given.', + 'Parameter #1 $object_or_class of function is_subclass_of expects object, class-string given.', 14, ], [ - 'Parameter #1 $object_or_class of function is_subclass_of expects object, string given.', + 'Parameter #1 $object_or_class of function is_subclass_of expects object, class-string given.', 17, ], ]; @@ -1247,15 +1247,15 @@ public function testIsSubclassAllowString(): void // php 7.x had different parameter names $errors = [ [ - 'Parameter #1 $object_or_string of function is_subclass_of expects object, string given.', + 'Parameter #1 $object_or_string of function is_subclass_of expects object, class-string given.', 11, ], [ - 'Parameter #1 $object_or_string of function is_subclass_of expects object, string given.', + 'Parameter #1 $object_or_string of function is_subclass_of expects object, class-string given.', 14, ], [ - 'Parameter #1 $object_or_string of function is_subclass_of expects object, string given.', + 'Parameter #1 $object_or_string of function is_subclass_of expects object, class-string given.', 17, ], ]; diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 7aca3e79a0b..70f7e0fa59b 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -507,7 +507,7 @@ public function testCallMethods(): void 1461, ], [ - 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, string given.', + 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, class-string given.', 1490, ], [ @@ -834,7 +834,7 @@ public function testCallMethodsOnThisOnly(): void 1379, ], [ - 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, string given.', + 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, class-string given.', 1490, ], [ diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index d7dc2805345..1c1b3e15f44 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -579,7 +579,7 @@ public function testTemplateTypeInOneBranchOfConditional(): void [ 'Parameter #1 $params of static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection() expects array{wrapperClass?: class-string}, array{wrapperClass: \'stdClass\'} given.', 27, - "Offset 'wrapperClass' (class-string) does not accept type string.", + "Offset 'wrapperClass' (class-string) does not accept type class-string.", ], [ 'Unable to resolve the template type T in call to static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection()', diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 1f3465af5d8..238a85fccc6 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -817,7 +817,7 @@ public function testBug8071(): void // there should be no errors 'Method Bug8071\Inheritance::inherit() should return array but returns array.', 17, - 'Type string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.', + "• Type class-string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.\n• Type string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.", ], ]); } @@ -1331,4 +1331,18 @@ public function testBug11430(): void $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-11430.php'], []); } + public function testBug14440(): void + { + $this->analyse([__DIR__ . '/data/bug-14440.php'], [ + [ + 'Method Bug14440\ChildOne::getCounterpartClass() should return class-string but returns class-string.', + 18, + ], + [ + 'Method Bug14440\ChildTwo::getCounterpartClass() should return class-string but returns class-string.', + 27, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-14440.php b/tests/PHPStan/Rules/Methods/data/bug-14440.php new file mode 100644 index 00000000000..7bf699ded15 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-14440.php @@ -0,0 +1,29 @@ + */ + abstract public static function getCounterpartClass(): string; +} + +final class ChildOne extends A implements I +{ + #[\Override] + public static function getCounterpartClass(): string + { + return ChildTwo::class; + } +} + +final class ChildTwo extends A implements I +{ + #[\Override] + public static function getCounterpartClass(): string + { + return ChildOne::class; + } +} From dc330b420b588a1f2f4715b0eb10912b48662ac7 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Wed, 8 Apr 2026 09:42:36 +0000 Subject: [PATCH 2/4] Move class-string verbosity logic to VerbosityLevel::getRecommendedLevelByType Instead of modifying ConstantStringType::describe() at typeOnly level, use VerbosityLevel to bump to value level when the accepting type contains class-string types. The class-string description is now shown at value verbosity level instead of typeOnly. Co-Authored-By: Claude Opus 4.6 --- src/Type/Constant/ConstantStringType.php | 16 +++++++++------- src/Type/VerbosityLevel.php | 4 ++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Type/Constant/ConstantStringType.php b/src/Type/Constant/ConstantStringType.php index 3497cdbfc3f..a5c8c0aca28 100644 --- a/src/Type/Constant/ConstantStringType.php +++ b/src/Type/Constant/ConstantStringType.php @@ -113,16 +113,18 @@ public function getObjectTypeOrClassStringObjectType(): Type public function describe(VerbosityLevel $level): string { return $level->handle( - fn (): string => $this->isClassString ? 'class-string<' . $this->value . '>' : 'string', + static fn (): string => 'string', function (): string { + if ($this->isClassString) { + return 'class-string<' . $this->value . '>'; + } + $value = $this->value; - if (!$this->isClassString) { - try { - $value = Strings::truncate($value, self::DESCRIBE_LIMIT); - } catch (RegexpException) { - $value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}"; - } + try { + $value = Strings::truncate($value, self::DESCRIBE_LIMIT); + } catch (RegexpException) { + $value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}"; } return self::export($value); diff --git a/src/Type/VerbosityLevel.php b/src/Type/VerbosityLevel.php index 32be9683a81..8560e134054 100644 --- a/src/Type/VerbosityLevel.php +++ b/src/Type/VerbosityLevel.php @@ -174,6 +174,10 @@ public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acc $moreVerbose = true; return $type; } + if ($type->isClassString()->yes()) { + $moreVerbose = true; + return $type; + } return $traverse($type); }; From 6fdce8df2fdf50d1aa90a44b6610546bfb6203fd Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Wed, 8 Apr 2026 09:42:42 +0000 Subject: [PATCH 3/4] Update test expectations for class-string value-level descriptions Tests now expect class-string instead of quoted 'ClassName' when ConstantStringType with isClassString flag is described at value verbosity level. Also update baseline and ignored error patterns. Co-Authored-By: Claude Opus 4.6 --- build/phpstan.neon | 4 ++-- phpstan-baseline.neon | 2 +- .../Rules/Classes/ClassAttributesRuleTest.php | 2 +- .../Classes/ImpossibleInstanceOfRuleTest.php | 4 ++-- ...mpossibleCheckTypeFunctionCallRuleTest.php | 24 +++++++++---------- .../ImpossibleCheckTypeMethodCallRuleTest.php | 2 +- ...rictComparisonOfDifferentTypesRuleTest.php | 18 +++++++------- .../Rules/Functions/CallCallablesRuleTest.php | 8 +++---- .../CallToFunctionParametersRuleTest.php | 20 ++++++++-------- .../Methods/CallStaticMethodsRuleTest.php | 8 +++---- .../Rules/Methods/ReturnTypeRuleTest.php | 2 +- .../TypesAssignedToPropertiesRuleTest.php | 2 +- 12 files changed, 48 insertions(+), 48 deletions(-) diff --git a/build/phpstan.neon b/build/phpstan.neon index 526f68798d2..7e94e384063 100644 --- a/build/phpstan.neon +++ b/build/phpstan.neon @@ -108,11 +108,11 @@ parameters: message: '#^Variable property access on T of PHPStan\\Rules\\RuleError\.$#' path: ../src/Rules/RuleErrorBuilder.php - - message: "#^Parameter \\#1 (?:\\$argument|\\$objectOrClass) of class ReflectionClass constructor expects class\\-string\\\\|PHPStan\\\\ExtensionInstaller\\\\GeneratedConfig, string given\\.$#" + message: "#^Parameter \\#1 (?:\\$argument|\\$objectOrClass) of class ReflectionClass constructor expects class\\-string\\\\|PHPStan\\\\ExtensionInstaller\\\\GeneratedConfig, 'PHPStan…' given\\.$#" count: 1 path: ../src/Command/CommandHelper.php - - message: "#^Parameter \\#1 (?:\\$argument|\\$objectOrClass) of class ReflectionClass constructor expects class\\-string\\\\|PHPStan\\\\ExtensionInstaller\\\\GeneratedConfig, string given\\.$#" + message: "#^Parameter \\#1 (?:\\$argument|\\$objectOrClass) of class ReflectionClass constructor expects class\\-string\\\\|PHPStan\\\\ExtensionInstaller\\\\GeneratedConfig, 'PHPStan…' given\\.$#" count: 1 path: ../src/Diagnose/PHPStanDiagnoseExtension.php - identifier: ternary.shortNotAllowed diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 971e51ec9fc..69092ef7a1d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -742,7 +742,7 @@ parameters: path: src/Rules/RuleLevelHelper.php - - rawMessage: 'Call to function method_exists() with ''PHPUnit\\Framework\\TestCase'' and ''assertFileDoesNotEx…'' will always evaluate to true.' + rawMessage: 'Call to function method_exists() with class-string and ''assertFileDoesNotEx…'' will always evaluate to true.' identifier: function.alreadyNarrowedType count: 1 path: src/Testing/LevelsTestCase.php diff --git a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php index cf65e01cf08..a6a5c343e9c 100644 --- a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php @@ -150,7 +150,7 @@ public function testBug7171(): void { $this->analyse([__DIR__ . '/data/bug-7171.php'], [ [ - 'Parameter $repositoryClass of attribute class Bug7171\Entity constructor expects class-string>|null, \'stdClass\' given.', + 'Parameter $repositoryClass of attribute class Bug7171\Entity constructor expects class-string>|null, class-string given.', 66, ], ]); diff --git a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php index fcc567c51d9..958710237a1 100644 --- a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php @@ -190,12 +190,12 @@ public function testInstanceof(): void $tipText, ], [ - 'Instanceof between class-string and \'DateTimeInterface\' will always evaluate to false.', + 'Instanceof between class-string and class-string will always evaluate to false.', 432, $tipText, ], [ - 'Instanceof between DateTimeInterface and \'DateTimeInterface\' will always evaluate to true.', + 'Instanceof between DateTimeInterface and class-string will always evaluate to true.', 433, $tipText, ], diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index cbb3ed25a77..e8649510449 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -160,7 +160,7 @@ public function testImpossibleCheckTypeFunctionCall(): void 582, ], [ - 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExists\' and \'testWithStringFirst…\' will always evaluate to true.', + 'Call to function method_exists() with class-string and \'testWithStringFirst…\' will always evaluate to true.', 596, ], [ @@ -196,30 +196,30 @@ public function testImpossibleCheckTypeFunctionCall(): void 656, ], [ - 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.', + 'Call to function method_exists() with class-string and \'method\' will always evaluate to true.', 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.', + 'Call to function method_exists() with class-string and \'someAnother\' will always evaluate to true.', 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.', + 'Call to function method_exists() with class-string and \'unknown\' will always evaluate to false.', 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.', + 'Call to function method_exists() with class-string and \'method\' will always evaluate to true.', 668, ], [ - 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.', + 'Call to function method_exists() with class-string and \'someAnother\' will always evaluate to true.', 671, ], [ - 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', + 'Call to function method_exists() with class-string and \'unknown\' will always evaluate to false.', 674, ], [ @@ -391,11 +391,11 @@ public function testBug6305(): void $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6305.php'], [ [ - 'Call to function is_subclass_of() with Bug6305\B and \'Bug6305\\\A\' will always evaluate to true.', + 'Call to function is_subclass_of() with Bug6305\B and class-string will always evaluate to true.', 11, ], [ - 'Call to function is_subclass_of() with Bug6305\B and \'Bug6305\\\B\' will always evaluate to false.', + 'Call to function is_subclass_of() with Bug6305\B and class-string will always evaluate to false.', 14, ], ]); @@ -412,11 +412,11 @@ public function testBug13713(): void $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-13713.php'], [ [ - "Call to function is_subclass_of() with arguments Bug13713\\test, 'stdClass' and false will always evaluate to true.", + "Call to function is_subclass_of() with arguments Bug13713\\test, class-string and false will always evaluate to true.", 12, ], [ - "Call to function is_subclass_of() with arguments class-string, 'stdClass' and true will always evaluate to true.", + "Call to function is_subclass_of() with arguments class-string, class-string and true will always evaluate to true.", 25, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], @@ -1004,7 +1004,7 @@ public function testBugPR3404(): void $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-pr-3404.php'], [ [ - 'Call to function is_a() with arguments BugPR3404\Location, \'BugPR3404\\\\Location\' and true will always evaluate to true.', + 'Call to function is_a() with arguments BugPR3404\Location, class-string and true will always evaluate to true.', 21, ], ]); diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php index 382dbc2f28a..b90b299d226 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php @@ -264,7 +264,7 @@ public function testBug12473(): void $tip, ],*/ [ - 'Call to method ReflectionClass::isSubclassOf() with \'Bug12473\\\\PictureProduct\' will always evaluate to false.', + 'Call to method ReflectionClass::isSubclassOf() with class-string will always evaluate to false.', 49, $tip, ], diff --git a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php index aa632593c79..516822df167 100644 --- a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php @@ -571,12 +571,12 @@ public function testBug3633(): void $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\HelloWorld\' and \'Bug3633\\\HelloWorld\' will always evaluate to true.', + 'Strict comparison using === between class-string and class-string will always evaluate to true.', 41, $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\HelloWorld\' and \'Bug3633\\\OtherClass\' will always evaluate to false.', + 'Strict comparison using === between class-string and class-string will always evaluate to false.', 44, ], [ @@ -585,12 +585,12 @@ public function testBug3633(): void $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\OtherClass\' and \'Bug3633\\\HelloWorld\' will always evaluate to false.', + 'Strict comparison using === between class-string and class-string will always evaluate to false.', 71, $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\OtherClass\' and \'Bug3633\\\OtherClass\' will always evaluate to true.', + 'Strict comparison using === between class-string and class-string will always evaluate to true.', 74, $tipText, ], @@ -605,27 +605,27 @@ public function testBug3633(): void $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to true.', + 'Strict comparison using === between class-string and class-string will always evaluate to true.', 102, $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\HelloWorld\' will always evaluate to false.', + 'Strict comparison using === between class-string and class-string will always evaluate to false.', 106, $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\OtherClass\' will always evaluate to false.', + 'Strict comparison using === between class-string and class-string will always evaluate to false.', 109, $tipText, ], [ - 'Strict comparison using !== between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to false.', + 'Strict comparison using !== between class-string and class-string will always evaluate to false.', 112, $tipText, ], [ - 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to true.', + 'Strict comparison using === between class-string and class-string will always evaluate to true.', 115, ], ]); diff --git a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php index 72f0f27e21e..35b47862ec0 100644 --- a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php @@ -148,22 +148,22 @@ public function testRule(): void 176, ], [ - 'Trying to invoke array{\'CallCallables\\\\CallableInForeach\', \'bar\'|\'foo\'} but it might not be a callable.', + 'Trying to invoke array{class-string, \'bar\'|\'foo\'} but it might not be a callable.', 188, ], [ - 'Trying to invoke array{\'CallCallables\\\\ConstantArrayUnionCallables\'|\'DateTimeImmutable\', \'doFoo\'} but it might not be a callable.', + 'Trying to invoke array{class-string|class-string, \'doFoo\'} but it might not be a callable.', 214, ], [ - 'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\', \'doBaz\'|\'doFoo\'} but it might not be a callable.', + 'Trying to invoke array{class-string, \'doBaz\'|\'doFoo\'} but it might not be a callable.', 221, ], ]; if (PHP_VERSION_ID >= 80000) { $errors[] = [ - 'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\'|\'CallCallables\\\ConstantArrayUnionCallablesTest\', \'doBar\'|\'doFoo\'} but it\'s not a callable.', + 'Trying to invoke array{class-string|class-string, \'doBar\'|\'doFoo\'} but it\'s not a callable.', 229, ]; } diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 406194352b0..dbc01b06364 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -1200,11 +1200,11 @@ public function testBug4371(): void { $errors = [ [ - 'Parameter #1 $object_or_class of function is_a expects object, class-string given.', + 'Parameter #1 $object_or_class of function is_a expects object, string given.', 14, ], [ - 'Parameter #1 $object_or_class of function is_a expects object, class-string given.', + 'Parameter #1 $object_or_class of function is_a expects object, string given.', 22, ], ]; @@ -1213,11 +1213,11 @@ public function testBug4371(): void // php 7.x had different parameter names $errors = [ [ - 'Parameter #1 $object_or_string of function is_a expects object, class-string given.', + 'Parameter #1 $object_or_string of function is_a expects object, string given.', 14, ], [ - 'Parameter #1 $object_or_string of function is_a expects object, class-string given.', + 'Parameter #1 $object_or_string of function is_a expects object, string given.', 22, ], ]; @@ -1230,15 +1230,15 @@ public function testIsSubclassAllowString(): void { $errors = [ [ - 'Parameter #1 $object_or_class of function is_subclass_of expects object, class-string given.', + 'Parameter #1 $object_or_class of function is_subclass_of expects object, string given.', 11, ], [ - 'Parameter #1 $object_or_class of function is_subclass_of expects object, class-string given.', + 'Parameter #1 $object_or_class of function is_subclass_of expects object, string given.', 14, ], [ - 'Parameter #1 $object_or_class of function is_subclass_of expects object, class-string given.', + 'Parameter #1 $object_or_class of function is_subclass_of expects object, string given.', 17, ], ]; @@ -1247,15 +1247,15 @@ public function testIsSubclassAllowString(): void // php 7.x had different parameter names $errors = [ [ - 'Parameter #1 $object_or_string of function is_subclass_of expects object, class-string given.', + 'Parameter #1 $object_or_string of function is_subclass_of expects object, string given.', 11, ], [ - 'Parameter #1 $object_or_string of function is_subclass_of expects object, class-string given.', + 'Parameter #1 $object_or_string of function is_subclass_of expects object, string given.', 14, ], [ - 'Parameter #1 $object_or_string of function is_subclass_of expects object, class-string given.', + 'Parameter #1 $object_or_string of function is_subclass_of expects object, string given.', 17, ], ]; diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index 1c1b3e15f44..8cbb6123a01 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -454,11 +454,11 @@ public function testBug4550(): void $this->checkThisOnly = false; $this->analyse([__DIR__ . '/data/bug-4550.php'], [ [ - 'Parameter #1 $class of static method Bug4550\Test::valuesOf() expects class-string, string given.', + "Parameter #1 \$class of static method Bug4550\Test::valuesOf() expects class-string, 'Person' given.", 34, ], [ - 'Parameter #1 $class of static method Bug4550\Test::valuesOf() expects class-string, string given.', + "Parameter #1 \$class of static method Bug4550\Test::valuesOf() expects class-string, 'Person' given.", 44, ], ]); @@ -482,7 +482,7 @@ public function testBug1971Php8(): void $this->checkThisOnly = false; $this->analyse([__DIR__ . '/data/bug-1971.php'], [ [ - 'Parameter #1 $callback of static method Closure::fromCallable() expects callable(): mixed, array{\'Bug1971\\\HelloWorld\', \'sayHello\'} given.', + 'Parameter #1 $callback of static method Closure::fromCallable() expects callable(): mixed, array{class-string, \'sayHello\'} given.', 14, ], [ @@ -577,7 +577,7 @@ public function testTemplateTypeInOneBranchOfConditional(): void $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/template-type-in-one-branch-of-conditional.php'], [ [ - 'Parameter #1 $params of static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection() expects array{wrapperClass?: class-string}, array{wrapperClass: \'stdClass\'} given.', + 'Parameter #1 $params of static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection() expects array{wrapperClass?: class-string}, array{wrapperClass: class-string} given.', 27, "Offset 'wrapperClass' (class-string) does not accept type class-string.", ], diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 238a85fccc6..54674eb600c 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -817,7 +817,7 @@ public function testBug8071(): void // there should be no errors 'Method Bug8071\Inheritance::inherit() should return array but returns array.', 17, - "• Type class-string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.\n• Type string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.", + 'Type string is not always the same as TValues. It breaks the contract for some argument types, typically subtypes.', ], ]); } diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 77a9b0e3c93..e4d5f735244 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -320,7 +320,7 @@ public function testAppendedArrayItemType(): void 20, ], [ - 'Property AppendedArrayItem\Foo::$callables (array) does not accept non-empty-array.', + 'Property AppendedArrayItem\Foo::$callables (array) does not accept non-empty-array, \'classMethod\'}|(callable(): mixed)>.', 23, ], [ From 1f38336b8011473eed2277ac6e906ee2c3981ab8 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Wed, 8 Apr 2026 10:22:04 +0000 Subject: [PATCH 4/4] Revert ConstantStringType::describe, only use VerbosityLevel for class-string Address review feedback: do not modify ConstantStringType::describe() at all. Instead, only add a class-string check in VerbosityLevel::getRecommendedLevelByType that bumps verbosity to value level when the accepting type is a class-string type. This means class-string constants show as quoted values (e.g. 'stdClass') at value verbosity, not as class-string. The verbosity is only bumped when the accepting type contains a class-string, so when a method expects object and receives a class-string, it still shows as just 'string'. Co-Authored-By: Claude Opus 4.6 --- phpstan-baseline.neon | 2 +- src/Type/Constant/ConstantStringType.php | 14 +++++------ src/Type/VerbosityLevel.php | 2 +- .../Rules/Classes/ClassAttributesRuleTest.php | 2 +- .../Classes/ImpossibleInstanceOfRuleTest.php | 4 ++-- ...mpossibleCheckTypeFunctionCallRuleTest.php | 24 +++++++++---------- .../ImpossibleCheckTypeMethodCallRuleTest.php | 2 +- ...rictComparisonOfDifferentTypesRuleTest.php | 18 +++++++------- .../Rules/Functions/CallCallablesRuleTest.php | 8 +++---- .../CallToFunctionParametersRuleTest.php | 2 +- .../Rules/Methods/CallMethodsRuleTest.php | 4 ++-- .../Methods/CallStaticMethodsRuleTest.php | 6 ++--- .../Rules/Methods/ReturnTypeRuleTest.php | 4 ++-- .../TypesAssignedToPropertiesRuleTest.php | 2 +- 14 files changed, 46 insertions(+), 48 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 69092ef7a1d..971e51ec9fc 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -742,7 +742,7 @@ parameters: path: src/Rules/RuleLevelHelper.php - - rawMessage: 'Call to function method_exists() with class-string and ''assertFileDoesNotEx…'' will always evaluate to true.' + rawMessage: 'Call to function method_exists() with ''PHPUnit\\Framework\\TestCase'' and ''assertFileDoesNotEx…'' will always evaluate to true.' identifier: function.alreadyNarrowedType count: 1 path: src/Testing/LevelsTestCase.php diff --git a/src/Type/Constant/ConstantStringType.php b/src/Type/Constant/ConstantStringType.php index a5c8c0aca28..40d0773c48d 100644 --- a/src/Type/Constant/ConstantStringType.php +++ b/src/Type/Constant/ConstantStringType.php @@ -115,16 +115,14 @@ public function describe(VerbosityLevel $level): string return $level->handle( static fn (): string => 'string', function (): string { - if ($this->isClassString) { - return 'class-string<' . $this->value . '>'; - } - $value = $this->value; - try { - $value = Strings::truncate($value, self::DESCRIBE_LIMIT); - } catch (RegexpException) { - $value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}"; + if (!$this->isClassString) { + try { + $value = Strings::truncate($value, self::DESCRIBE_LIMIT); + } catch (RegexpException) { + $value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}"; + } } return self::export($value); diff --git a/src/Type/VerbosityLevel.php b/src/Type/VerbosityLevel.php index 8560e134054..7cd72a1d32f 100644 --- a/src/Type/VerbosityLevel.php +++ b/src/Type/VerbosityLevel.php @@ -174,7 +174,7 @@ public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acc $moreVerbose = true; return $type; } - if ($type->isClassString()->yes()) { + if ($type->isString()->yes() && $type->isClassString()->yes()) { $moreVerbose = true; return $type; } diff --git a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php index a6a5c343e9c..cf65e01cf08 100644 --- a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php @@ -150,7 +150,7 @@ public function testBug7171(): void { $this->analyse([__DIR__ . '/data/bug-7171.php'], [ [ - 'Parameter $repositoryClass of attribute class Bug7171\Entity constructor expects class-string>|null, class-string given.', + 'Parameter $repositoryClass of attribute class Bug7171\Entity constructor expects class-string>|null, \'stdClass\' given.', 66, ], ]); diff --git a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php index 958710237a1..fcc567c51d9 100644 --- a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php @@ -190,12 +190,12 @@ public function testInstanceof(): void $tipText, ], [ - 'Instanceof between class-string and class-string will always evaluate to false.', + 'Instanceof between class-string and \'DateTimeInterface\' will always evaluate to false.', 432, $tipText, ], [ - 'Instanceof between DateTimeInterface and class-string will always evaluate to true.', + 'Instanceof between DateTimeInterface and \'DateTimeInterface\' will always evaluate to true.', 433, $tipText, ], diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index e8649510449..cbb3ed25a77 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -160,7 +160,7 @@ public function testImpossibleCheckTypeFunctionCall(): void 582, ], [ - 'Call to function method_exists() with class-string and \'testWithStringFirst…\' will always evaluate to true.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExists\' and \'testWithStringFirst…\' will always evaluate to true.', 596, ], [ @@ -196,30 +196,30 @@ public function testImpossibleCheckTypeFunctionCall(): void 656, ], [ - 'Call to function method_exists() with class-string and \'method\' will always evaluate to true.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.', 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 class-string and \'someAnother\' will always evaluate to true.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.', 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 class-string and \'unknown\' will always evaluate to false.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', 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 class-string and \'method\' will always evaluate to true.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.', 668, ], [ - 'Call to function method_exists() with class-string and \'someAnother\' will always evaluate to true.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.', 671, ], [ - 'Call to function method_exists() with class-string and \'unknown\' will always evaluate to false.', + 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', 674, ], [ @@ -391,11 +391,11 @@ public function testBug6305(): void $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6305.php'], [ [ - 'Call to function is_subclass_of() with Bug6305\B and class-string will always evaluate to true.', + 'Call to function is_subclass_of() with Bug6305\B and \'Bug6305\\\A\' will always evaluate to true.', 11, ], [ - 'Call to function is_subclass_of() with Bug6305\B and class-string will always evaluate to false.', + 'Call to function is_subclass_of() with Bug6305\B and \'Bug6305\\\B\' will always evaluate to false.', 14, ], ]); @@ -412,11 +412,11 @@ public function testBug13713(): void $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-13713.php'], [ [ - "Call to function is_subclass_of() with arguments Bug13713\\test, class-string and false will always evaluate to true.", + "Call to function is_subclass_of() with arguments Bug13713\\test, 'stdClass' and false will always evaluate to true.", 12, ], [ - "Call to function is_subclass_of() with arguments class-string, class-string and true will always evaluate to true.", + "Call to function is_subclass_of() with arguments class-string, 'stdClass' and true will always evaluate to true.", 25, 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], @@ -1004,7 +1004,7 @@ public function testBugPR3404(): void $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-pr-3404.php'], [ [ - 'Call to function is_a() with arguments BugPR3404\Location, class-string and true will always evaluate to true.', + 'Call to function is_a() with arguments BugPR3404\Location, \'BugPR3404\\\\Location\' and true will always evaluate to true.', 21, ], ]); diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php index b90b299d226..382dbc2f28a 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php @@ -264,7 +264,7 @@ public function testBug12473(): void $tip, ],*/ [ - 'Call to method ReflectionClass::isSubclassOf() with class-string will always evaluate to false.', + 'Call to method ReflectionClass::isSubclassOf() with \'Bug12473\\\\PictureProduct\' will always evaluate to false.', 49, $tip, ], diff --git a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php index 516822df167..aa632593c79 100644 --- a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php @@ -571,12 +571,12 @@ public function testBug3633(): void $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to true.', + 'Strict comparison using === between \'Bug3633\\\HelloWorld\' and \'Bug3633\\\HelloWorld\' will always evaluate to true.', 41, $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to false.', + 'Strict comparison using === between \'Bug3633\\\HelloWorld\' and \'Bug3633\\\OtherClass\' will always evaluate to false.', 44, ], [ @@ -585,12 +585,12 @@ public function testBug3633(): void $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to false.', + 'Strict comparison using === between \'Bug3633\\\OtherClass\' and \'Bug3633\\\HelloWorld\' will always evaluate to false.', 71, $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to true.', + 'Strict comparison using === between \'Bug3633\\\OtherClass\' and \'Bug3633\\\OtherClass\' will always evaluate to true.', 74, $tipText, ], @@ -605,27 +605,27 @@ public function testBug3633(): void $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to true.', + 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to true.', 102, $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to false.', + 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\HelloWorld\' will always evaluate to false.', 106, $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to false.', + 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\OtherClass\' will always evaluate to false.', 109, $tipText, ], [ - 'Strict comparison using !== between class-string and class-string will always evaluate to false.', + 'Strict comparison using !== between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to false.', 112, $tipText, ], [ - 'Strict comparison using === between class-string and class-string will always evaluate to true.', + 'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to true.', 115, ], ]); diff --git a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php index 35b47862ec0..72f0f27e21e 100644 --- a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php @@ -148,22 +148,22 @@ public function testRule(): void 176, ], [ - 'Trying to invoke array{class-string, \'bar\'|\'foo\'} but it might not be a callable.', + 'Trying to invoke array{\'CallCallables\\\\CallableInForeach\', \'bar\'|\'foo\'} but it might not be a callable.', 188, ], [ - 'Trying to invoke array{class-string|class-string, \'doFoo\'} but it might not be a callable.', + 'Trying to invoke array{\'CallCallables\\\\ConstantArrayUnionCallables\'|\'DateTimeImmutable\', \'doFoo\'} but it might not be a callable.', 214, ], [ - 'Trying to invoke array{class-string, \'doBaz\'|\'doFoo\'} but it might not be a callable.', + 'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\', \'doBaz\'|\'doFoo\'} but it might not be a callable.', 221, ], ]; if (PHP_VERSION_ID >= 80000) { $errors[] = [ - 'Trying to invoke array{class-string|class-string, \'doBar\'|\'doFoo\'} but it\'s not a callable.', + 'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\'|\'CallCallables\\\ConstantArrayUnionCallablesTest\', \'doBar\'|\'doFoo\'} but it\'s not a callable.', 229, ]; } diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index dbc01b06364..36f8ce54a75 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -1161,7 +1161,7 @@ public function testBug4413(): void require_once __DIR__ . '/data/bug-4413.php'; $this->analyse([__DIR__ . '/data/bug-4413.php'], [ [ - 'Parameter #1 $date of function Bug4413\takesDate expects class-string, class-string given.', + 'Parameter #1 $date of function Bug4413\takesDate expects class-string, \'stdClass\' given.', 18, ], ]); diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 70f7e0fa59b..fcde4582f19 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -507,7 +507,7 @@ public function testCallMethods(): void 1461, ], [ - 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, class-string given.', + 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, \'Throwable\' given.', 1490, ], [ @@ -834,7 +834,7 @@ public function testCallMethodsOnThisOnly(): void 1379, ], [ - 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, class-string given.', + 'Parameter #1 $s of method Test\ClassStringWithUpperBounds::doFoo() expects class-string, \'Throwable\' given.', 1490, ], [ diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index 8cbb6123a01..67ad92622be 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -482,7 +482,7 @@ public function testBug1971Php8(): void $this->checkThisOnly = false; $this->analyse([__DIR__ . '/data/bug-1971.php'], [ [ - 'Parameter #1 $callback of static method Closure::fromCallable() expects callable(): mixed, array{class-string, \'sayHello\'} given.', + 'Parameter #1 $callback of static method Closure::fromCallable() expects callable(): mixed, array{\'Bug1971\\\HelloWorld\', \'sayHello\'} given.', 14, ], [ @@ -577,9 +577,9 @@ public function testTemplateTypeInOneBranchOfConditional(): void $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/template-type-in-one-branch-of-conditional.php'], [ [ - 'Parameter #1 $params of static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection() expects array{wrapperClass?: class-string}, array{wrapperClass: class-string} given.', + 'Parameter #1 $params of static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection() expects array{wrapperClass?: class-string}, array{wrapperClass: \'stdClass\'} given.', 27, - "Offset 'wrapperClass' (class-string) does not accept type class-string.", + "Offset 'wrapperClass' (class-string) does not accept type 'stdClass'.", ], [ 'Unable to resolve the template type T in call to static method TemplateTypeInOneBranchOfConditional\DriverManager::getConnection()', diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 54674eb600c..4ced8dcb0e1 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -1335,11 +1335,11 @@ public function testBug14440(): void { $this->analyse([__DIR__ . '/data/bug-14440.php'], [ [ - 'Method Bug14440\ChildOne::getCounterpartClass() should return class-string but returns class-string.', + 'Method Bug14440\ChildOne::getCounterpartClass() should return class-string but returns \'Bug14440\\\\ChildTwo\'.', 18, ], [ - 'Method Bug14440\ChildTwo::getCounterpartClass() should return class-string but returns class-string.', + 'Method Bug14440\ChildTwo::getCounterpartClass() should return class-string but returns \'Bug14440\\\\ChildOne\'.', 27, ], ]); diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index e4d5f735244..77a9b0e3c93 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -320,7 +320,7 @@ public function testAppendedArrayItemType(): void 20, ], [ - 'Property AppendedArrayItem\Foo::$callables (array) does not accept non-empty-array, \'classMethod\'}|(callable(): mixed)>.', + 'Property AppendedArrayItem\Foo::$callables (array) does not accept non-empty-array.', 23, ], [