Skip to content

Commit a743a3a

Browse files
committed
Added support for ConstantString unions in RequireExtendsRule
1 parent 4f2408e commit a743a3a

File tree

3 files changed

+72
-32
lines changed

3 files changed

+72
-32
lines changed

src/Rules/Classes/RequireExtendsRule.php

+34-32
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use PHPStan\Rules\Rule;
99
use PHPStan\Rules\RuleErrorBuilder;
1010
use PHPStan\Type\VerbosityLevel;
11-
use function count;
1211
use function sprintf;
1312

1413
/**
@@ -35,46 +34,49 @@ public function processNode(Node $node, Scope $scope): array
3534
$extendsTags = $interface->getRequireExtendsTags();
3635
foreach ($extendsTags as $extendsTag) {
3736
$type = $extendsTag->getType();
38-
$classNames = $type->getObjectClassNames();
39-
if (count($classNames) === 1 && $classReflection->is($classNames[0])) {
40-
continue;
41-
}
37+
foreach ($type->getObjectClassNames() as $className) {
38+
if ($classReflection->is($className)) {
39+
continue;
40+
}
41+
42+
$errors[] = RuleErrorBuilder::message(
43+
sprintf(
44+
'Interface %s requires implementing class to extend %s, but %s does not.',
45+
$interface->getDisplayName(),
46+
$type->describe(VerbosityLevel::typeOnly()),
47+
$classReflection->getDisplayName(),
48+
),
49+
)
50+
->identifier('class.missingExtends')
51+
->build();
4252

43-
$errors[] = RuleErrorBuilder::message(
44-
sprintf(
45-
'Interface %s requires implementing class to extend %s, but %s does not.',
46-
$interface->getDisplayName(),
47-
$type->describe(VerbosityLevel::typeOnly()),
48-
$classReflection->getDisplayName(),
49-
),
50-
)
51-
->identifier('class.missingExtends')
52-
->build();
53+
break;
54+
}
5355
}
5456
}
5557

5658
foreach ($classReflection->getTraits(true) as $trait) {
5759
$extendsTags = $trait->getRequireExtendsTags();
5860
foreach ($extendsTags as $extendsTag) {
5961
$type = $extendsTag->getType();
60-
$classNames = $type->getObjectClassNames();
61-
if (count($classNames) === 0) {
62-
continue;
63-
}
64-
if (count($classNames) === 1 && $classReflection->is($classNames[0])) {
65-
continue;
66-
}
62+
foreach ($type->getObjectClassNames() as $className) {
63+
if ($classReflection->is($className)) {
64+
continue;
65+
}
66+
67+
$errors[] = RuleErrorBuilder::message(
68+
sprintf(
69+
'Trait %s requires using class to extend %s, but %s does not.',
70+
$trait->getDisplayName(),
71+
$type->describe(VerbosityLevel::typeOnly()),
72+
$classReflection->getDisplayName(),
73+
),
74+
)
75+
->identifier('class.missingExtends')
76+
->build();
6777

68-
$errors[] = RuleErrorBuilder::message(
69-
sprintf(
70-
'Trait %s requires using class to extend %s, but %s does not.',
71-
$trait->getDisplayName(),
72-
$type->describe(VerbosityLevel::typeOnly()),
73-
$classReflection->getDisplayName(),
74-
),
75-
)
76-
->identifier('class.missingExtends')
77-
->build();
78+
break;
79+
}
7880
}
7981
}
8082

tests/PHPStan/Rules/Classes/RequireExtendsRuleTest.php

+16
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ public function testRule(): void
5252
'Trait IncompatibleRequireExtends\ValidPsalmTrait requires using class to extend IncompatibleRequireExtends\SomeClass, but class@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-extends.php:163 does not.',
5353
163,
5454
],
55+
[
56+
'Interface IncompatibleRequireExtends\RequireNonExisstentUnionClassinterface requires implementing class to extend IncompatibleRequireExtends\NonExistentClass|IncompatibleRequireExtends\SomeClass, but IncompatibleRequireExtends\RequireNonExisstentUnionClassinterface@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-extends.php:185 does not.',
57+
185,
58+
],
59+
[
60+
'Interface IncompatibleRequireExtends\RequireNonExisstentUnionClassinterface requires implementing class to extend IncompatibleRequireExtends\NonExistentClass|IncompatibleRequireExtends\SomeClass, but IncompatibleRequireExtends\SomeClass@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-extends.php:187 does not.',
61+
187,
62+
],
63+
[
64+
'Trait IncompatibleRequireExtends\RequireNonExisstentUnionClassTrait requires using class to extend IncompatibleRequireExtends\NonExistentClass|IncompatibleRequireExtends\SomeClass, but class@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-extends.php:194 does not.',
65+
194,
66+
],
67+
[
68+
'Trait IncompatibleRequireExtends\RequireNonExisstentUnionClassTrait requires using class to extend IncompatibleRequireExtends\NonExistentClass|IncompatibleRequireExtends\SomeClass, but IncompatibleRequireExtends\SomeClass@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-extends.php:198 does not.',
69+
198,
70+
],
5571
];
5672

5773
$this->analyse([__DIR__ . '/../PhpDoc/data/incompatible-require-extends.php'], $expectedErrors);

tests/PHPStan/Rules/PhpDoc/data/incompatible-require-extends.php

+22
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,25 @@ trait TooMuchExtends {}
176176
* @phpstan-require-extends SomeOtherClass
177177
*/
178178
interface TooMuchExtendsIface {}
179+
180+
/**
181+
* @phpstan-require-extends SomeClass|NonExistentClass
182+
*/
183+
interface RequireNonExisstentUnionClassinterface {}
184+
185+
new class implements RequireNonExisstentUnionClassinterface {};
186+
187+
new class extends SomeClass implements RequireNonExisstentUnionClassinterface {};
188+
189+
/**
190+
* @phpstan-require-extends SomeClass|NonExistentClass
191+
*/
192+
trait RequireNonExisstentUnionClassTrait {}
193+
194+
new class {
195+
use RequireNonExisstentUnionClassTrait;
196+
};
197+
198+
new class extends SomeClass {
199+
use RequireNonExisstentUnionClassTrait;
200+
};

0 commit comments

Comments
 (0)