Skip to content

Commit 0b15a01

Browse files
committed
report missing template types with regard to optional templates
1 parent 86c307b commit 0b15a01

29 files changed

+248
-34
lines changed

src/Rules/Classes/LocalTypeAliasesCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use PHPStan\Type\VerbosityLevel;
2525
use function array_key_exists;
2626
use function array_merge;
27-
use function implode;
2827
use function in_array;
2928
use function sprintf;
3029

@@ -211,7 +210,7 @@ public function checkInTraitDefinitionContext(ClassReflection $reflection): arra
211210
$reflection->getDisplayName(),
212211
$aliasName,
213212
$name,
214-
implode(', ', $genericTypeNames),
213+
$genericTypeNames,
215214
))
216215
->identifier('missingType.generics')
217216
->build();

src/Rules/Classes/MethodTagCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use PHPStan\Type\Type;
1717
use PHPStan\Type\VerbosityLevel;
1818
use function array_merge;
19-
use function implode;
2019
use function sprintf;
2120

2221
final class MethodTagCheck
@@ -174,7 +173,7 @@ private function checkMethodTypeInTraitDefinitionContext(ClassReflection $classR
174173
$methodName,
175174
$description,
176175
$innerName,
177-
implode(', ', $genericTypeNames),
176+
$genericTypeNames,
178177
))
179178
->identifier('missingType.generics')
180179
->build();

src/Rules/Classes/MixinCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use PHPStan\Rules\RuleErrorBuilder;
1515
use PHPStan\Type\VerbosityLevel;
1616
use function array_merge;
17-
use function implode;
1817
use function sprintf;
1918

2019
final class MixinCheck
@@ -90,7 +89,7 @@ public function checkInTraitDefinitionContext(ClassReflection $classReflection):
9089
$errors[] = RuleErrorBuilder::message(sprintf(
9190
'PHPDoc tag @mixin contains generic %s but does not specify its types: %s',
9291
$innerName,
93-
implode(', ', $genericTypeNames),
92+
$genericTypeNames,
9493
))
9594
->identifier('missingType.generics')
9695
->build();

src/Rules/Classes/PropertyTagCheck.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use PHPStan\Type\Type;
1919
use PHPStan\Type\VerbosityLevel;
2020
use function array_merge;
21-
use function implode;
2221
use function sprintf;
2322

2423
final class PropertyTagCheck
@@ -155,7 +154,7 @@ private function checkPropertyTypeInTraitDefinitionContext(ClassReflection $clas
155154
$classReflection->getDisplayName(),
156155
$propertyName,
157156
$innerName,
158-
implode(', ', $genericTypeNames),
157+
$genericTypeNames,
159158
))
160159
->identifier('missingType.generics')
161160
->build();

src/Rules/Constants/MissingClassConstantTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use PHPStan\ShouldNotHappenException;
1313
use PHPStan\Type\VerbosityLevel;
1414
use function array_merge;
15-
use function implode;
1615
use function sprintf;
1716

1817
/**
@@ -76,7 +75,7 @@ private function processSingleConstant(ClassReflection $classReflection, string
7675
$constantReflection->getDeclaringClass()->getDisplayName(),
7776
$constantName,
7877
$name,
79-
implode(', ', $genericTypeNames),
78+
$genericTypeNames,
8079
))
8180
->identifier('missingType.generics')
8281
->build();

src/Rules/Functions/MissingFunctionParameterTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use PHPStan\Type\MixedType;
1414
use PHPStan\Type\Type;
1515
use PHPStan\Type\VerbosityLevel;
16-
use function implode;
1716
use function sprintf;
1817

1918
/**
@@ -100,7 +99,7 @@ private function checkFunctionParameter(FunctionReflection $functionReflection,
10099
$functionReflection->getName(),
101100
$parameterMessage,
102101
$name,
103-
implode(', ', $genericTypeNames),
102+
$genericTypeNames,
104103
))
105104
->identifier('missingType.generics')
106105
->build();

src/Rules/Functions/MissingFunctionReturnTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use PHPStan\Rules\RuleErrorBuilder;
1111
use PHPStan\Type\MixedType;
1212
use PHPStan\Type\VerbosityLevel;
13-
use function implode;
1413
use function sprintf;
1514

1615
/**
@@ -58,7 +57,7 @@ public function processNode(Node $node, Scope $scope): array
5857
'Function %s() return type with generic %s does not specify its types: %s',
5958
$functionReflection->getName(),
6059
$name,
61-
implode(', ', $genericTypeNames),
60+
$genericTypeNames,
6261
))
6362
->identifier('missingType.generics')
6463
->build();

src/Rules/Generics/GenericAncestorsCheck.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
1010
use PHPStan\Rules\RuleErrorBuilder;
1111
use PHPStan\Type\Generic\GenericObjectType;
12+
use PHPStan\Type\Generic\TemplateType;
1213
use PHPStan\Type\Generic\TemplateTypeVariance;
1314
use PHPStan\Type\Generic\TypeProjectionHelper;
1415
use PHPStan\Type\Type;
1516
use PHPStan\Type\VerbosityLevel;
1617
use function array_fill_keys;
18+
use function array_filter;
1719
use function array_keys;
1820
use function array_map;
1921
use function array_merge;
@@ -173,10 +175,22 @@ public function check(
173175
continue;
174176
}
175177

178+
$templateTypes = $unusedNameClassReflection->getTemplateTypeMap()->getTypes();
179+
$templateTypesCount = count($templateTypes);
180+
$requiredTemplateTypesCount = count(array_filter($templateTypes, static fn (Type $type) => $type instanceof TemplateType && $type->getDefault() === null));
181+
if ($requiredTemplateTypesCount === 0) {
182+
continue;
183+
}
184+
185+
$templateTypesList = implode(', ', array_keys($templateTypes));
186+
if ($requiredTemplateTypesCount !== $templateTypesCount) {
187+
$templateTypesList .= sprintf(' (%d-%d required)', $requiredTemplateTypesCount, $templateTypesCount);
188+
}
189+
176190
$messages[] = RuleErrorBuilder::message(sprintf(
177191
$genericClassInNonGenericObjectType,
178192
$unusedName,
179-
implode(', ', array_keys($unusedNameClassReflection->getTemplateTypeMap()->getTypes())),
193+
$templateTypesList,
180194
))
181195
->identifier('missingType.generics')
182196
->build();

src/Rules/Generics/GenericObjectTypeCheck.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPStan\Type\Type;
1515
use PHPStan\Type\TypeTraverser;
1616
use PHPStan\Type\VerbosityLevel;
17+
use function array_filter;
1718
use function array_keys;
1819
use function array_values;
1920
use function count;
@@ -59,27 +60,37 @@ public function check(
5960
$genericTypeVariances = $genericType->getVariances();
6061
$templateTypesCount = count($templateTypes);
6162
$genericTypeTypesCount = count($genericTypeTypes);
62-
if ($templateTypesCount > $genericTypeTypesCount) {
63+
$requiredTemplateTypesCount = count(array_filter($templateTypes, static fn (Type $type) => $type instanceof TemplateType && $type->getDefault() === null));
64+
if ($requiredTemplateTypesCount > $genericTypeTypesCount) {
65+
$templateTypesList = implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes()));
66+
if ($requiredTemplateTypesCount !== $templateTypesCount) {
67+
$templateTypesList .= sprintf(' (%d-%d required).', $requiredTemplateTypesCount, $templateTypesCount);
68+
}
69+
6370
$messages[] = RuleErrorBuilder::message(sprintf(
6471
$notEnoughTypesMessage,
6572
$genericType->describe(VerbosityLevel::typeOnly()),
6673
$classLikeDescription,
6774
$classReflection->getDisplayName(false),
68-
implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes())),
75+
$templateTypesList,
6976
))->identifier('generics.lessTypes')->build();
7077
} elseif ($templateTypesCount < $genericTypeTypesCount) {
78+
$templateTypesList = implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes()));
79+
if ($requiredTemplateTypesCount !== $templateTypesCount) {
80+
$templateTypesList .= sprintf(' (%d-%d required)', $requiredTemplateTypesCount, $templateTypesCount);
81+
}
82+
7183
$messages[] = RuleErrorBuilder::message(sprintf(
7284
$extraTypesMessage,
7385
$genericType->describe(VerbosityLevel::typeOnly()),
7486
$genericTypeTypesCount,
7587
$classLikeDescription,
7688
$classReflection->getDisplayName(false),
7789
$templateTypesCount,
78-
implode(', ', array_keys($classReflection->getTemplateTypeMap()->getTypes())),
90+
$templateTypesList,
7991
))->identifier('generics.moreTypes')->build();
8092
}
8193

82-
$templateTypesCount = count($templateTypes);
8394
for ($i = 0; $i < $templateTypesCount; $i++) {
8495
if (!isset($genericTypeTypes[$i])) {
8596
continue;

src/Rules/Methods/MissingMethodParameterTypehintRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use PHPStan\Type\MixedType;
1414
use PHPStan\Type\Type;
1515
use PHPStan\Type\VerbosityLevel;
16-
use function implode;
1716
use function sprintf;
1817

1918
/**
@@ -103,7 +102,7 @@ private function checkMethodParameter(MethodReflection $methodReflection, string
103102
$methodReflection->getName(),
104103
$parameterMessage,
105104
$name,
106-
implode(', ', $genericTypeNames),
105+
$genericTypeNames,
107106
))
108107
->identifier('missingType.generics')
109108
->build();

0 commit comments

Comments
 (0)