Skip to content

Commit

Permalink
Call GenericObjectTypeCheck from IncompatibleSelfOutTypeRule
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Aug 23, 2024
1 parent d389ae0 commit 9ebc315
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/PhpDoc/StubValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
$container->getParameter('featureToggles')['invalidPhpDocTagLine'],
),
new IncompatibleParamImmediatelyInvokedCallableRule($fileTypeMapper),
new IncompatibleSelfOutTypeRule($unresolvableTypeHelper),
new IncompatibleSelfOutTypeRule($unresolvableTypeHelper, $genericObjectTypeCheck),
new IncompatibleClassConstantPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper),
new InvalidThrowsPhpDocValueRule($fileTypeMapper),

Expand Down
38 changes: 36 additions & 2 deletions src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Internal\SprintfHelper;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Rules\Generics\GenericObjectTypeCheck;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectType;
use PHPStan\Type\VerbosityLevel;
use function array_merge;
use function sprintf;

/**
Expand All @@ -17,7 +20,10 @@
final class IncompatibleSelfOutTypeRule implements Rule
{

public function __construct(private UnresolvableTypeHelper $unresolvableTypeHelper)
public function __construct(
private UnresolvableTypeHelper $unresolvableTypeHelper,
private GenericObjectTypeCheck $genericObjectTypeCheck,
)
{
}

Expand Down Expand Up @@ -63,7 +69,35 @@ public function processNode(Node $node, Scope $scope): array
))->identifier('parameter.unresolvableType')->build();
}

return $errors;
$escapedTagName = SprintfHelper::escapeFormatString('@phpstan-self-out');

return array_merge($errors, $this->genericObjectTypeCheck->check(
$selfOutType,
sprintf(
'PHPDoc tag %s contains generic type %%s but %%s %%s is not generic.',
$escapedTagName,
),
sprintf(
'Generic type %%s in PHPDoc tag %s does not specify all template types of %%s %%s: %%s',
$escapedTagName,
),
sprintf(
'Generic type %%s in PHPDoc tag %s specifies %%d template types, but %%s %%s supports only %%d: %%s',
$escapedTagName,
),
sprintf(
'Type %%s in generic type %%s in PHPDoc tag %s is not subtype of template type %%s of %%s %%s.',
$escapedTagName,
),
sprintf(
'Call-site variance of %%s in generic type %%s in PHPDoc tag %s is in conflict with %%s template type %%s of %%s %%s.',
$escapedTagName,
),
sprintf(
'Call-site variance of %%s in generic type %%s in PHPDoc tag %s is redundant, template type %%s of %%s %%s has the same variance.',
$escapedTagName,
),
));
}

}
19 changes: 18 additions & 1 deletion tests/PHPStan/Rules/PhpDoc/IncompatibleSelfOutTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PHPStan\Rules\PhpDoc;

use PHPStan\Rules\Generics\GenericObjectTypeCheck;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

Expand All @@ -13,7 +14,7 @@ class IncompatibleSelfOutTypeRuleTest extends RuleTestCase

protected function getRule(): Rule
{
return new IncompatibleSelfOutTypeRule(new UnresolvableTypeHelper());
return new IncompatibleSelfOutTypeRule(new UnresolvableTypeHelper(), new GenericObjectTypeCheck());
}

public function testRule(): void
Expand All @@ -39,6 +40,22 @@ public function testRule(): void
'PHPDoc tag @phpstan-self-out for method IncompatibleSelfOutType\Foo::doBar() contains unresolvable type.',
54,
],
[
'PHPDoc tag @phpstan-self-out contains generic type IncompatibleSelfOutType\GenericCheck<int> but class IncompatibleSelfOutType\GenericCheck is not generic.',
67,
],
[
'Generic type IncompatibleSelfOutType\GenericCheck2<InvalidArgumentException> in PHPDoc tag @phpstan-self-out does not specify all template types of class IncompatibleSelfOutType\GenericCheck2: T, U',
84,
],
[
'Generic type IncompatibleSelfOutType\GenericCheck2<InvalidArgumentException, int<1, max>, string> in PHPDoc tag @phpstan-self-out specifies 3 template types, but class IncompatibleSelfOutType\GenericCheck2 supports only 2: T, U',
92,
],
[
'Type string in generic type IncompatibleSelfOutType\GenericCheck2<InvalidArgumentException, string> in PHPDoc tag @phpstan-self-out is not subtype of template type U of int of class IncompatibleSelfOutType\GenericCheck2.',
100,
],
]);
}

Expand Down
46 changes: 46 additions & 0 deletions tests/PHPStan/Rules/PhpDoc/data/incompatible-self-out-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,49 @@ public function doBar(): void
}

}

class GenericCheck
{

/**
* @phpstan-self-out self<int>
*/
public function doFoo(): void
{

}

}

/**
* @template T of \Exception
* @template U of int
*/
class GenericCheck2
{

/**
* @phpstan-self-out self<\InvalidArgumentException>
*/
public function doFoo(): void
{

}

/**
* @phpstan-self-out self<\InvalidArgumentException, positive-int, string>
*/
public function doFoo2(): void
{

}

/**
* @phpstan-self-out self<\InvalidArgumentException, string>
*/
public function doFoo3(): void
{

}

}

0 comments on commit 9ebc315

Please sign in to comment.