Skip to content

Commit 2ebbb53

Browse files
committed
ConstructorReturnTypeRule
1 parent 52969a1 commit 2ebbb53

File tree

5 files changed

+153
-0
lines changed

5 files changed

+153
-0
lines changed

conf/config.level0.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ rules:
7575
- PHPStan\Rules\Methods\AbstractMethodInNonAbstractClassRule
7676
- PHPStan\Rules\Methods\CallMethodsRule
7777
- PHPStan\Rules\Methods\CallStaticMethodsRule
78+
- PHPStan\Rules\Methods\ConstructorReturnTypeRule
7879
- PHPStan\Rules\Methods\ExistingClassesInTypehintsRule
7980
- PHPStan\Rules\Methods\FinalPrivateMethodRule
8081
- PHPStan\Rules\Methods\MethodCallableRule

src/Analyser/NodeScopeResolver.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4369,6 +4369,7 @@ private function processNodesForTraitUse($node, ClassReflection $traitReflection
43694369
continue;
43704370
}
43714371

4372+
$methodAst->setAttribute('originalTraitMethodName', $methodAst->name->toLowerString());
43724373
$methodAst->name = $methodNames[$methodName];
43734374
}
43744375
$this->processStmtNodes($node, $stmts, $scope->enterTrait($traitReflection), $nodeCallback, StatementContext::createTopLevel());
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Methods;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Node\InClassMethodNode;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
use function sprintf;
11+
12+
/**
13+
* @implements Rule<InClassMethodNode>
14+
*/
15+
class ConstructorReturnTypeRule implements Rule
16+
{
17+
18+
public function getNodeType(): string
19+
{
20+
return InClassMethodNode::class;
21+
}
22+
23+
public function processNode(Node $node, Scope $scope): array
24+
{
25+
$classReflection = $node->getClassReflection();
26+
$methodNode = $node->getOriginalNode();
27+
if ($scope->isInTrait()) {
28+
$originalMethodName = $methodNode->getAttribute('originalTraitMethodName');
29+
if (
30+
$originalMethodName === '__construct'
31+
&& $methodNode->returnType !== null
32+
) {
33+
return [
34+
RuleErrorBuilder::message(sprintf('Original constructor of trait %s has a return type.', $scope->getTraitReflection()->getDisplayName()))
35+
->identifier('constructor.returnType')
36+
->nonIgnorable()
37+
->build(),
38+
];
39+
}
40+
}
41+
if (!$classReflection->hasConstructor()) {
42+
return [];
43+
}
44+
45+
$constructorReflection = $classReflection->getConstructor();
46+
$methodReflection = $node->getMethodReflection();
47+
if ($methodReflection->getName() !== $constructorReflection->getName()) {
48+
return [];
49+
}
50+
51+
if ($methodNode->returnType === null) {
52+
return [];
53+
}
54+
55+
return [
56+
RuleErrorBuilder::message(sprintf('Constructor of class %s has a return type.', $classReflection->getDisplayName()))
57+
->identifier('constructor.returnType')
58+
->nonIgnorable()
59+
->build(),
60+
];
61+
}
62+
63+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Methods;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Testing\RuleTestCase;
7+
8+
/**
9+
* @extends RuleTestCase<ConstructorReturnTypeRule>
10+
*/
11+
class ConstructorReturnTypeRuleTest extends RuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new ConstructorReturnTypeRule();
17+
}
18+
19+
public function testRule(): void
20+
{
21+
$this->analyse([__DIR__ . '/data/constructor-return-type.php'], [
22+
[
23+
'Constructor of class ConstructorReturnType\Bar has a return type.',
24+
17,
25+
],
26+
[
27+
'Constructor of class ConstructorReturnType\UsesFooTrait has a return type.',
28+
26,
29+
],
30+
[
31+
'Original constructor of trait ConstructorReturnType\BarTrait has a return type.',
32+
35,
33+
],
34+
]);
35+
}
36+
37+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace ConstructorReturnType;
4+
5+
class Foo
6+
{
7+
8+
public function __construct()
9+
{
10+
}
11+
12+
}
13+
14+
class Bar
15+
{
16+
17+
public function __construct(): void
18+
{
19+
}
20+
21+
}
22+
23+
trait FooTrait
24+
{
25+
26+
public function __construct(): void
27+
{
28+
}
29+
30+
}
31+
32+
trait BarTrait
33+
{
34+
35+
public function __construct(): void
36+
{
37+
}
38+
39+
}
40+
41+
class UsesFooTrait
42+
{
43+
use FooTrait;
44+
}
45+
46+
class RenamesBarTrait
47+
{
48+
use BarTrait {
49+
__construct as baseConstructor;
50+
}
51+
}

0 commit comments

Comments
 (0)