Skip to content

Commit

Permalink
Bleeding edge - MethodTagTemplateTypeTraitRule
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Sep 3, 2024
1 parent 085fcf4 commit aadbf62
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 0 deletions.
5 changes: 5 additions & 0 deletions conf/config.level2.neon
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ conditionalTags:
phpstan.rules.rule: %featureToggles.closureDefaultParameterTypeRule%
PHPStan\Rules\Functions\IncompatibleClosureDefaultParameterTypeRule:
phpstan.rules.rule: %featureToggles.closureDefaultParameterTypeRule%
PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule:
phpstan.rules.rule: %featureToggles.absentTypeChecks%
PHPStan\Rules\Methods\IllegalConstructorMethodCallRule:
phpstan.rules.rule: %featureToggles.illegalConstructorMethodCall%
PHPStan\Rules\Methods\IllegalConstructorStaticCallRule:
Expand Down Expand Up @@ -127,6 +129,9 @@ services:
reportMaybes: %reportMaybes%
tags:
- phpstan.rules.rule

-
class: PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule
-
class: PHPStan\Rules\Methods\IllegalConstructorMethodCallRule
-
Expand Down
2 changes: 2 additions & 0 deletions src/PhpDoc/StubValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
use PHPStan\Rules\Generics\MethodSignatureVarianceRule;
use PHPStan\Rules\Generics\MethodTagTemplateTypeCheck;
use PHPStan\Rules\Generics\MethodTagTemplateTypeRule;
use PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule;
use PHPStan\Rules\Generics\MethodTemplateTypeRule;
use PHPStan\Rules\Generics\TemplateTypeCheck;
use PHPStan\Rules\Generics\TraitTemplateTypeRule;
Expand Down Expand Up @@ -257,6 +258,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
$rules[] = new PropertyTagTraitUseRule($propertyTagCheck);
$rules[] = new MixinRule($reflectionProvider, $classNameCheck, $genericObjectTypeCheck, $missingTypehintCheck, $unresolvableTypeHelper, true, true);
$rules[] = new LocalTypeTraitUseAliasesRule($localTypeAliasesCheck);
$rules[] = new MethodTagTemplateTypeTraitRule($methodTagTemplateTypeCheck, $reflectionProvider);
}

return new DirectRuleRegistry($rules);
Expand Down
52 changes: 52 additions & 0 deletions src/Rules/Generics/MethodTagTemplateTypeTraitRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Generics;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;

/**
* @implements Rule<Node\Stmt\Trait_>
*/
final class MethodTagTemplateTypeTraitRule implements Rule
{

public function __construct(
private MethodTagTemplateTypeCheck $check,
private ReflectionProvider $reflectionProvider,
)
{
}

public function getNodeType(): string
{
return Node\Stmt\Trait_::class;
}

public function processNode(Node $node, Scope $scope): array
{
$docComment = $node->getDocComment();
if ($docComment === null) {
return [];
}

$traitName = $node->namespacedName;
if ($traitName === null) {
return [];
}

if (!$this->reflectionProvider->hasClass($traitName->toString())) {
return [];
}

return $this->check->check(
$this->reflectionProvider->getClass($traitName->toString()),
$scope,
$node,
$docComment->getText(),
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Generics;

use PHPStan\Rules\ClassCaseSensitivityCheck;
use PHPStan\Rules\ClassForbiddenNameCheck;
use PHPStan\Rules\ClassNameCheck;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPStan\Type\FileTypeMapper;

/**
* @extends RuleTestCase<MethodTagTemplateTypeTraitRule>
*/
class MethodTagTemplateTypeTraitRuleTest extends RuleTestCase
{

protected function getRule(): Rule
{
$reflectionProvider = $this->createReflectionProvider();
$typeAliasResolver = $this->createTypeAliasResolver(['TypeAlias' => 'int'], $reflectionProvider);

return new MethodTagTemplateTypeTraitRule(
new MethodTagTemplateTypeCheck(
self::getContainer()->getByType(FileTypeMapper::class),
new TemplateTypeCheck(
$reflectionProvider,
new ClassNameCheck(
new ClassCaseSensitivityCheck($reflectionProvider, true),
new ClassForbiddenNameCheck(self::getContainer()),
),
new GenericObjectTypeCheck(),
$typeAliasResolver,
true,
),
),
$reflectionProvider,
);
}

public function testRule(): void
{
$this->analyse([__DIR__ . '/data/method-tag-trait-template.php'], [
[
'PHPDoc tag @method template U for method MethodTagTraitTemplate\HelloWorld::sayHello() has invalid bound type MethodTagTraitTemplate\Nonexisting.',
11,
],
[
'PHPDoc tag @method template for method MethodTagTraitTemplate\HelloWorld::sayHello() cannot have existing class stdClass as its name.',
11,
],
[
'PHPDoc tag @method template T for method MethodTagTraitTemplate\HelloWorld::sayHello() shadows @template T for class MethodTagTraitTemplate\HelloWorld.',
11,
],
[
'PHPDoc tag @method template for method MethodTagTraitTemplate\HelloWorld::typeAlias() cannot have existing type alias TypeAlias as its name.',
11,
],
]);
}

}
13 changes: 13 additions & 0 deletions tests/PHPStan/Rules/Generics/data/method-tag-trait-template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types = 1);

namespace MethodTagTraitTemplate;

/**
* @template T
*
* @method void sayHello<T, U of Nonexisting, stdClass>(T $a, U $b, stdClass $c)
* @method void typeAlias<TypeAlias of mixed>(TypeAlias $a)
*/
trait HelloWorld
{
}

0 comments on commit aadbf62

Please sign in to comment.