Skip to content

Commit 1f38336

Browse files
phpstan-botclaude
andcommitted
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<ClassName>. 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 <noreply@anthropic.com>
1 parent 6fdce8d commit 1f38336

14 files changed

Lines changed: 46 additions & 48 deletions

phpstan-baseline.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ parameters:
742742
path: src/Rules/RuleLevelHelper.php
743743

744744
-
745-
rawMessage: 'Call to function method_exists() with class-string<PHPUnit\Framework\TestCase> and ''assertFileDoesNotEx…'' will always evaluate to true.'
745+
rawMessage: 'Call to function method_exists() with ''PHPUnit\\Framework\\TestCase'' and ''assertFileDoesNotEx…'' will always evaluate to true.'
746746
identifier: function.alreadyNarrowedType
747747
count: 1
748748
path: src/Testing/LevelsTestCase.php

src/Type/Constant/ConstantStringType.php

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,14 @@ public function describe(VerbosityLevel $level): string
115115
return $level->handle(
116116
static fn (): string => 'string',
117117
function (): string {
118-
if ($this->isClassString) {
119-
return 'class-string<' . $this->value . '>';
120-
}
121-
122118
$value = $this->value;
123119

124-
try {
125-
$value = Strings::truncate($value, self::DESCRIBE_LIMIT);
126-
} catch (RegexpException) {
127-
$value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}";
120+
if (!$this->isClassString) {
121+
try {
122+
$value = Strings::truncate($value, self::DESCRIBE_LIMIT);
123+
} catch (RegexpException) {
124+
$value = substr($value, 0, self::DESCRIBE_LIMIT) . "\u{2026}";
125+
}
128126
}
129127

130128
return self::export($value);

src/Type/VerbosityLevel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public static function getRecommendedLevelByType(Type $acceptingType, ?Type $acc
174174
$moreVerbose = true;
175175
return $type;
176176
}
177-
if ($type->isClassString()->yes()) {
177+
if ($type->isString()->yes() && $type->isClassString()->yes()) {
178178
$moreVerbose = true;
179179
return $type;
180180
}

tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public function testBug7171(): void
150150
{
151151
$this->analyse([__DIR__ . '/data/bug-7171.php'], [
152152
[
153-
'Parameter $repositoryClass of attribute class Bug7171\Entity constructor expects class-string<Bug7171\EntityRepository<T of object>>|null, class-string<stdClass> given.',
153+
'Parameter $repositoryClass of attribute class Bug7171\Entity constructor expects class-string<Bug7171\EntityRepository<T of object>>|null, \'stdClass\' given.',
154154
66,
155155
],
156156
]);

tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,12 @@ public function testInstanceof(): void
190190
$tipText,
191191
],
192192
[
193-
'Instanceof between class-string<DateTimeInterface> and class-string<DateTimeInterface> will always evaluate to false.',
193+
'Instanceof between class-string<DateTimeInterface> and \'DateTimeInterface\' will always evaluate to false.',
194194
432,
195195
$tipText,
196196
],
197197
[
198-
'Instanceof between DateTimeInterface and class-string<DateTimeInterface> will always evaluate to true.',
198+
'Instanceof between DateTimeInterface and \'DateTimeInterface\' will always evaluate to true.',
199199
433,
200200
$tipText,
201201
],

tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public function testImpossibleCheckTypeFunctionCall(): void
160160
582,
161161
],
162162
[
163-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\\MethodExists> and \'testWithStringFirst…\' will always evaluate to true.',
163+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExists\' and \'testWithStringFirst…\' will always evaluate to true.',
164164
596,
165165
],
166166
[
@@ -196,30 +196,30 @@ public function testImpossibleCheckTypeFunctionCall(): void
196196
656,
197197
],
198198
[
199-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\MethodExistsWithTrait> and \'method\' will always evaluate to true.',
199+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.',
200200
659,
201201
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
202202
],
203203
[
204-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\MethodExistsWithTrait> and \'someAnother\' will always evaluate to true.',
204+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.',
205205
662,
206206
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
207207
],
208208
[
209-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\MethodExistsWithTrait> and \'unknown\' will always evaluate to false.',
209+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.',
210210
665,
211211
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
212212
],
213213
[
214-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\MethodExistsWithTrait> and \'method\' will always evaluate to true.',
214+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'method\' will always evaluate to true.',
215215
668,
216216
],
217217
[
218-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\MethodExistsWithTrait> and \'someAnother\' will always evaluate to true.',
218+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'someAnother\' will always evaluate to true.',
219219
671,
220220
],
221221
[
222-
'Call to function method_exists() with class-string<CheckTypeFunctionCall\MethodExistsWithTrait> and \'unknown\' will always evaluate to false.',
222+
'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.',
223223
674,
224224
],
225225
[
@@ -391,11 +391,11 @@ public function testBug6305(): void
391391
$this->treatPhpDocTypesAsCertain = true;
392392
$this->analyse([__DIR__ . '/data/bug-6305.php'], [
393393
[
394-
'Call to function is_subclass_of() with Bug6305\B and class-string<Bug6305\A> will always evaluate to true.',
394+
'Call to function is_subclass_of() with Bug6305\B and \'Bug6305\\\A\' will always evaluate to true.',
395395
11,
396396
],
397397
[
398-
'Call to function is_subclass_of() with Bug6305\B and class-string<Bug6305\B> will always evaluate to false.',
398+
'Call to function is_subclass_of() with Bug6305\B and \'Bug6305\\\B\' will always evaluate to false.',
399399
14,
400400
],
401401
]);
@@ -412,11 +412,11 @@ public function testBug13713(): void
412412
$this->treatPhpDocTypesAsCertain = true;
413413
$this->analyse([__DIR__ . '/data/bug-13713.php'], [
414414
[
415-
"Call to function is_subclass_of() with arguments Bug13713\\test, class-string<stdClass> and false will always evaluate to true.",
415+
"Call to function is_subclass_of() with arguments Bug13713\\test, 'stdClass' and false will always evaluate to true.",
416416
12,
417417
],
418418
[
419-
"Call to function is_subclass_of() with arguments class-string<Bug13713\\test>, class-string<stdClass> and true will always evaluate to true.",
419+
"Call to function is_subclass_of() with arguments class-string<Bug13713\\test>, 'stdClass' and true will always evaluate to true.",
420420
25,
421421
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
422422
],
@@ -1004,7 +1004,7 @@ public function testBugPR3404(): void
10041004
$this->treatPhpDocTypesAsCertain = true;
10051005
$this->analyse([__DIR__ . '/data/bug-pr-3404.php'], [
10061006
[
1007-
'Call to function is_a() with arguments BugPR3404\Location, class-string<BugPR3404\\Location> and true will always evaluate to true.',
1007+
'Call to function is_a() with arguments BugPR3404\Location, \'BugPR3404\\\\Location\' and true will always evaluate to true.',
10081008
21,
10091009
],
10101010
]);

tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ public function testBug12473(): void
264264
$tip,
265265
],*/
266266
[
267-
'Call to method ReflectionClass<Bug12473\\PictureUser>::isSubclassOf() with class-string<Bug12473\\PictureProduct> will always evaluate to false.',
267+
'Call to method ReflectionClass<Bug12473\\PictureUser>::isSubclassOf() with \'Bug12473\\\\PictureProduct\' will always evaluate to false.',
268268
49,
269269
$tip,
270270
],

tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -571,12 +571,12 @@ public function testBug3633(): void
571571
$tipText,
572572
],
573573
[
574-
'Strict comparison using === between class-string<Bug3633\HelloWorld> and class-string<Bug3633\HelloWorld> will always evaluate to true.',
574+
'Strict comparison using === between \'Bug3633\\\HelloWorld\' and \'Bug3633\\\HelloWorld\' will always evaluate to true.',
575575
41,
576576
$tipText,
577577
],
578578
[
579-
'Strict comparison using === between class-string<Bug3633\HelloWorld> and class-string<Bug3633\OtherClass> will always evaluate to false.',
579+
'Strict comparison using === between \'Bug3633\\\HelloWorld\' and \'Bug3633\\\OtherClass\' will always evaluate to false.',
580580
44,
581581
],
582582
[
@@ -585,12 +585,12 @@ public function testBug3633(): void
585585
$tipText,
586586
],
587587
[
588-
'Strict comparison using === between class-string<Bug3633\OtherClass> and class-string<Bug3633\HelloWorld> will always evaluate to false.',
588+
'Strict comparison using === between \'Bug3633\\\OtherClass\' and \'Bug3633\\\HelloWorld\' will always evaluate to false.',
589589
71,
590590
$tipText,
591591
],
592592
[
593-
'Strict comparison using === between class-string<Bug3633\OtherClass> and class-string<Bug3633\OtherClass> will always evaluate to true.',
593+
'Strict comparison using === between \'Bug3633\\\OtherClass\' and \'Bug3633\\\OtherClass\' will always evaluate to true.',
594594
74,
595595
$tipText,
596596
],
@@ -605,27 +605,27 @@ public function testBug3633(): void
605605
$tipText,
606606
],
607607
[
608-
'Strict comparison using === between class-string<Bug3633\FinalClass> and class-string<Bug3633\FinalClass> will always evaluate to true.',
608+
'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to true.',
609609
102,
610610
$tipText,
611611
],
612612
[
613-
'Strict comparison using === between class-string<Bug3633\FinalClass> and class-string<Bug3633\HelloWorld> will always evaluate to false.',
613+
'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\HelloWorld\' will always evaluate to false.',
614614
106,
615615
$tipText,
616616
],
617617
[
618-
'Strict comparison using === between class-string<Bug3633\FinalClass> and class-string<Bug3633\OtherClass> will always evaluate to false.',
618+
'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\OtherClass\' will always evaluate to false.',
619619
109,
620620
$tipText,
621621
],
622622
[
623-
'Strict comparison using !== between class-string<Bug3633\FinalClass> and class-string<Bug3633\FinalClass> will always evaluate to false.',
623+
'Strict comparison using !== between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to false.',
624624
112,
625625
$tipText,
626626
],
627627
[
628-
'Strict comparison using === between class-string<Bug3633\FinalClass> and class-string<Bug3633\FinalClass> will always evaluate to true.',
628+
'Strict comparison using === between \'Bug3633\\\FinalClass\' and \'Bug3633\\\FinalClass\' will always evaluate to true.',
629629
115,
630630
],
631631
]);

tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,22 +148,22 @@ public function testRule(): void
148148
176,
149149
],
150150
[
151-
'Trying to invoke array{class-string<CallCallables\\CallableInForeach>, \'bar\'|\'foo\'} but it might not be a callable.',
151+
'Trying to invoke array{\'CallCallables\\\\CallableInForeach\', \'bar\'|\'foo\'} but it might not be a callable.',
152152
188,
153153
],
154154
[
155-
'Trying to invoke array{class-string<CallCallables\\ConstantArrayUnionCallables>|class-string<DateTimeImmutable>, \'doFoo\'} but it might not be a callable.',
155+
'Trying to invoke array{\'CallCallables\\\\ConstantArrayUnionCallables\'|\'DateTimeImmutable\', \'doFoo\'} but it might not be a callable.',
156156
214,
157157
],
158158
[
159-
'Trying to invoke array{class-string<CallCallables\\ConstantArrayUnionCallables>, \'doBaz\'|\'doFoo\'} but it might not be a callable.',
159+
'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\', \'doBaz\'|\'doFoo\'} but it might not be a callable.',
160160
221,
161161
],
162162
];
163163

164164
if (PHP_VERSION_ID >= 80000) {
165165
$errors[] = [
166-
'Trying to invoke array{class-string<CallCallables\\ConstantArrayUnionCallables>|class-string<CallCallables\\ConstantArrayUnionCallablesTest>, \'doBar\'|\'doFoo\'} but it\'s not a callable.',
166+
'Trying to invoke array{\'CallCallables\\\ConstantArrayUnionCallables\'|\'CallCallables\\\ConstantArrayUnionCallablesTest\', \'doBar\'|\'doFoo\'} but it\'s not a callable.',
167167
229,
168168
];
169169
}

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,7 @@ public function testBug4413(): void
11611161
require_once __DIR__ . '/data/bug-4413.php';
11621162
$this->analyse([__DIR__ . '/data/bug-4413.php'], [
11631163
[
1164-
'Parameter #1 $date of function Bug4413\takesDate expects class-string<DateTime>, class-string<stdClass> given.',
1164+
'Parameter #1 $date of function Bug4413\takesDate expects class-string<DateTime>, \'stdClass\' given.',
11651165
18,
11661166
],
11671167
]);

0 commit comments

Comments
 (0)