diff --git a/src/Rules/Classes/LocalTypeAliasesCheck.php b/src/Rules/Classes/LocalTypeAliasesCheck.php index cd6362f8dd..71e807ecd7 100644 --- a/src/Rules/Classes/LocalTypeAliasesCheck.php +++ b/src/Rules/Classes/LocalTypeAliasesCheck.php @@ -4,12 +4,14 @@ use PhpParser\Node\Stmt\ClassLike; use PHPStan\Analyser\NameScope; +use PHPStan\Internal\SprintfHelper; use PHPStan\PhpDoc\TypeNodeResolver; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\ClassNameCheck; use PHPStan\Rules\ClassNameNodePair; +use PHPStan\Rules\Generics\GenericObjectTypeCheck; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\MissingTypehintCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; @@ -39,6 +41,7 @@ public function __construct( private MissingTypehintCheck $missingTypehintCheck, private ClassNameCheck $classCheck, private UnresolvableTypeHelper $unresolvableTypeHelper, + private GenericObjectTypeCheck $genericObjectTypeCheck, private bool $checkMissingTypehints, private bool $checkClassCaseSensitivity, private bool $absentTypeChecks, @@ -256,6 +259,35 @@ public function check(ClassReflection $reflection, ClassLike $node): array ->identifier('typeAlias.unresolvableType') ->build(); } + + $escapedTypeAlias = SprintfHelper::escapeFormatString($aliasName); + $errors = array_merge($errors, $this->genericObjectTypeCheck->check( + $resolvedType, + sprintf( + 'Type alias %s contains generic type %%s but %%s %%s is not generic.', + $escapedTypeAlias, + ), + sprintf( + 'Generic type %%s in type alias %s does not specify all template types of %%s %%s: %%s', + $escapedTypeAlias, + ), + sprintf( + 'Generic type %%s in type alias %s specifies %%d template types, but %%s %%s supports only %%d: %%s', + $escapedTypeAlias, + ), + sprintf( + 'Type %%s in generic type %%s in type alias %s is not subtype of template type %%s of %%s %%s.', + $escapedTypeAlias, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in type alias %s is in conflict with %%s template type %%s of %%s %%s.', + $escapedTypeAlias, + ), + sprintf( + 'Call-site variance of %%s in generic type %%s in type alias %s is redundant, template type %%s of %%s %%s has the same variance.', + $escapedTypeAlias, + ), + )); } return $errors; diff --git a/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php index 089014a7ae..e8c07ca171 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php @@ -6,6 +6,7 @@ use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; use PHPStan\Rules\ClassNameCheck; +use PHPStan\Rules\Generics\GenericObjectTypeCheck; use PHPStan\Rules\MissingTypehintCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; use PHPStan\Rules\Rule; @@ -33,6 +34,7 @@ protected function getRule(): Rule new ClassForbiddenNameCheck(self::getContainer()), ), new UnresolvableTypeHelper(), + new GenericObjectTypeCheck(), true, true, true, @@ -137,6 +139,10 @@ public function testRule(): void 'Type alias A contains unresolvable type.', 95, ], + [ + 'Type alias A contains generic type Exception but class Exception is not generic.', + 103, + ], ]); } diff --git a/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php index 1f53ff745c..1501b40f79 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php @@ -6,6 +6,7 @@ use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; use PHPStan\Rules\ClassNameCheck; +use PHPStan\Rules\Generics\GenericObjectTypeCheck; use PHPStan\Rules\MissingTypehintCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; use PHPStan\Rules\Rule; @@ -32,6 +33,7 @@ protected function getRule(): Rule new ClassForbiddenNameCheck(self::getContainer()), ), new UnresolvableTypeHelper(), + new GenericObjectTypeCheck(), true, true, true, diff --git a/tests/PHPStan/Rules/Classes/data/local-type-aliases.php b/tests/PHPStan/Rules/Classes/data/local-type-aliases.php index 5aa52e9082..152e77d8d7 100644 --- a/tests/PHPStan/Rules/Classes/data/local-type-aliases.php +++ b/tests/PHPStan/Rules/Classes/data/local-type-aliases.php @@ -96,3 +96,11 @@ class UnresolvableExample { } + +/** + * @phpstan-type A = \Exception + */ +class GenericsCheck +{ + +}