Skip to content

Commit ba59142

Browse files
committedSep 3, 2024
MixinCheck - prepare for trait rules
1 parent 57ccd8c commit ba59142

File tree

1 file changed

+79
-36
lines changed

1 file changed

+79
-36
lines changed
 

‎src/Rules/Classes/MixinCheck.php

+79-36
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,25 @@ public function __construct(
3737
*/
3838
public function check(ClassReflection $classReflection, ClassLike $node): array
3939
{
40-
$mixinTags = $classReflection->getMixinTags();
4140
$errors = [];
42-
foreach ($mixinTags as $mixinTag) {
41+
foreach ($this->checkInTraitDefinitionContext($classReflection) as $error) {
42+
$errors[] = $error;
43+
}
44+
45+
foreach ($this->checkInTraitUseContext($classReflection, $classReflection, $node) as $error) {
46+
$errors[] = $error;
47+
}
48+
49+
return $errors;
50+
}
51+
52+
/**
53+
* @return list<IdentifierRuleError>
54+
*/
55+
public function checkInTraitDefinitionContext(ClassReflection $classReflection): array
56+
{
57+
$errors = [];
58+
foreach ($classReflection->getMixinTags() as $mixinTag) {
4359
$type = $mixinTag->getType();
4460
if (!$type->canCallMethods()->yes() || !$type->canAccessProperties()->yes()) {
4561
$errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @mixin contains non-object type %s.', $type->describe(VerbosityLevel::typeOnly())))
@@ -48,6 +64,67 @@ public function check(ClassReflection $classReflection, ClassLike $node): array
4864
continue;
4965
}
5066

67+
if (!$this->absentTypeChecks) {
68+
continue;
69+
}
70+
71+
foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($type) as $iterableType) {
72+
$iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly());
73+
$errors[] = RuleErrorBuilder::message(sprintf(
74+
'%s %s has PHPDoc tag @mixin with no value type specified in iterable type %s.',
75+
$classReflection->getClassTypeDescription(),
76+
$classReflection->getDisplayName(),
77+
$iterableTypeDescription,
78+
))
79+
->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP)
80+
->identifier('missingType.iterableValue')
81+
->build();
82+
}
83+
84+
foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($type) as [$innerName, $genericTypeNames]) {
85+
$errors[] = RuleErrorBuilder::message(sprintf(
86+
'PHPDoc tag @mixin contains generic %s but does not specify its types: %s',
87+
$innerName,
88+
implode(', ', $genericTypeNames),
89+
))
90+
->identifier('missingType.generics')
91+
->build();
92+
}
93+
94+
foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($type) as $callableType) {
95+
$errors[] = RuleErrorBuilder::message(sprintf(
96+
'%s %s has PHPDoc tag @mixin with no signature specified for %s.',
97+
$classReflection->getClassTypeDescription(),
98+
$classReflection->getDisplayName(),
99+
$callableType->describe(VerbosityLevel::typeOnly()),
100+
))->identifier('missingType.callable')->build();
101+
}
102+
}
103+
104+
return $errors;
105+
}
106+
107+
/**
108+
* @return list<IdentifierRuleError>
109+
*/
110+
public function checkInTraitUseContext(
111+
ClassReflection $reflection,
112+
ClassReflection $implementingClassReflection,
113+
ClassLike $node,
114+
): array
115+
{
116+
if ($reflection->getNativeReflection()->getName() === $implementingClassReflection->getName()) {
117+
$phpDoc = $reflection->getResolvedPhpDoc();
118+
} else {
119+
$phpDoc = $reflection->getTraitContextResolvedPhpDoc($implementingClassReflection);
120+
}
121+
if ($phpDoc === null) {
122+
return [];
123+
}
124+
125+
$errors = [];
126+
foreach ($phpDoc->getMixinTags() as $mixinTag) {
127+
$type = $mixinTag->getType();
51128
if (
52129
$this->unresolvableTypeHelper->containsUnresolvableType($type)
53130
) {
@@ -67,40 +144,6 @@ public function check(ClassReflection $classReflection, ClassLike $node): array
67144
'Call-site variance of %s in generic type %s in PHPDoc tag @mixin is redundant, template type %s of %s %s has the same variance.',
68145
));
69146

70-
foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($type) as [$innerName, $genericTypeNames]) {
71-
$errors[] = RuleErrorBuilder::message(sprintf(
72-
'PHPDoc tag @mixin contains generic %s but does not specify its types: %s',
73-
$innerName,
74-
implode(', ', $genericTypeNames),
75-
))
76-
->identifier('missingType.generics')
77-
->build();
78-
}
79-
80-
if ($this->absentTypeChecks) {
81-
foreach ($this->missingTypehintCheck->getIterableTypesWithMissingValueTypehint($type) as $iterableType) {
82-
$iterableTypeDescription = $iterableType->describe(VerbosityLevel::typeOnly());
83-
$errors[] = RuleErrorBuilder::message(sprintf(
84-
'%s %s has PHPDoc tag @mixin with no value type specified in iterable type %s.',
85-
$classReflection->getClassTypeDescription(),
86-
$classReflection->getDisplayName(),
87-
$iterableTypeDescription,
88-
))
89-
->tip(MissingTypehintCheck::MISSING_ITERABLE_VALUE_TYPE_TIP)
90-
->identifier('missingType.iterableValue')
91-
->build();
92-
}
93-
94-
foreach ($this->missingTypehintCheck->getCallablesWithMissingSignature($type) as $callableType) {
95-
$errors[] = RuleErrorBuilder::message(sprintf(
96-
'%s %s has PHPDoc tag @mixin with no signature specified for %s.',
97-
$classReflection->getClassTypeDescription(),
98-
$classReflection->getDisplayName(),
99-
$callableType->describe(VerbosityLevel::typeOnly()),
100-
))->identifier('missingType.callable')->build();
101-
}
102-
}
103-
104147
foreach ($type->getReferencedClasses() as $class) {
105148
if (!$this->reflectionProvider->hasClass($class)) {
106149
$errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @mixin contains unknown class %s.', $class))

0 commit comments

Comments
 (0)
Please sign in to comment.