Skip to content

Commit 01bbd7f

Browse files
committed
feat: support class-string and similar PHPdoc types
1 parent 77eea9d commit 01bbd7f

File tree

2 files changed

+58
-23
lines changed

2 files changed

+58
-23
lines changed

rules/phpdocs_basic.php

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -157,34 +157,17 @@ function local_moodlecheck_functionarguments(local_moodlecheck_file $file) {
157157
// Must be at least type and parameter name.
158158
$match = false;
159159
} else {
160-
$expectedtype = local_moodlecheck_normalise_function_type((string) $function->arguments[$i][0]);
160+
$expectedtype = local_moodlecheck_normalise_function_type((string)$function->arguments[$i][0]);
161161
$expectedparam = (string)$function->arguments[$i][1];
162-
$documentedtype = local_moodlecheck_normalise_function_type((string) $documentedarguments[$i][0]);
162+
$documentedtype = local_moodlecheck_normalise_function_type((string)$documentedarguments[$i][0]);
163163
$documentedparam = $documentedarguments[$i][1];
164164

165-
$typematch = $expectedtype === $documentedtype;
166-
$parammatch = $expectedparam === $documentedparam;
167-
if ($typematch && $parammatch) {
168-
continue;
165+
if ($expectedparam !== $documentedparam) {
166+
$match = false;
169167
}
170168

171-
// Documented types can be a collection (| separated).
172-
foreach (explode('|', $documentedtype) as $documentedtype) {
173-
// Ignore null. They cannot match any type in function.
174-
if (trim($documentedtype) === 'null') {
175-
continue;
176-
}
177-
178-
if (strlen($expectedtype) && $expectedtype !== $documentedtype) {
179-
// It could be a type hinted array.
180-
if ($expectedtype !== 'array' || substr($documentedtype, -2) !== '[]') {
181-
$match = false;
182-
}
183-
} else if ($documentedtype === 'type') {
184-
$match = false;
185-
} else if ($expectedparam !== $documentedparam) {
186-
$match = false;
187-
}
169+
if (!local_moodlecheck_is_documented_type_allowed($expectedtype, $documentedtype)) {
170+
$match = false;
188171
}
189172
}
190173
}
@@ -204,6 +187,49 @@ function local_moodlecheck_functionarguments(local_moodlecheck_file $file) {
204187
return $errors;
205188
}
206189

190+
/**
191+
* Checks if a documented type is allowed for a parameter with the given real type declaration.
192+
*
193+
* @param string $expectedtype the real type declaration
194+
* @param string $documentedtype the type documented in PHPdoc
195+
* @return bool true if allowed, false if not
196+
*/
197+
function local_moodlecheck_is_documented_type_allowed(string $expectedtype, string $documentedtype): bool {
198+
if ($expectedtype === $documentedtype) {
199+
return true;
200+
}
201+
202+
// Documented types can be a collection (| separated).
203+
foreach (explode('|', $documentedtype) as $documentedtype) {
204+
// Ignore null. They cannot match any type in function.
205+
if (trim($documentedtype) === 'null') {
206+
continue;
207+
}
208+
209+
if (strlen($expectedtype) && $expectedtype !== $documentedtype) {
210+
// Allow type-hinted arrays.
211+
if ($expectedtype === 'array' && substr($documentedtype, -2) === '[]') {
212+
continue;
213+
}
214+
215+
$withoutgenerics = substr($documentedtype, 0, strpos($documentedtype, "<")) ?: $documentedtype;
216+
// Allow class-string<T> and the like for a string parameter.
217+
if ($expectedtype === 'string' && in_array($withoutgenerics,
218+
["class-string", "interface-string", "trait-string", "enum-string", "callable-string",
219+
"numeric-string", "literal-string", "lowercase-string", "non-empty-string",
220+
"non-empty-lowercase-string"])) {
221+
continue;
222+
}
223+
224+
return false;
225+
} else if ($documentedtype === 'type') {
226+
return false;
227+
}
228+
}
229+
230+
return true;
231+
}
232+
207233
/**
208234
* Normalise function type to be able to compare it.
209235
*

tests/fixtures/phpdoc_tags_general.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ public function correct_param_types5(string $one, ...$params) {
213213
echo "yay!";
214214
}
215215

216+
/**
217+
* Correct param types.
218+
*
219+
* @param class-string $myclass
220+
*/
221+
public function correct_param_types6(string $myclass) {
222+
echo "yay!";
223+
}
224+
216225
/**
217226
* Incomplete return annotation (type is missing).
218227
*

0 commit comments

Comments
 (0)