Skip to content

Commit 3cf3684

Browse files
try validating void
phpunit is too slow locally
1 parent 41ecc97 commit 3cf3684

16 files changed

+174
-0
lines changed

src/Rules/FunctionDefinitionCheck.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpParser\Node\Identifier;
1111
use PhpParser\Node\IntersectionType;
1212
use PhpParser\Node\Name;
13+
use PhpParser\Node\Name\FullyQualified;
1314
use PhpParser\Node\NullableType;
1415
use PhpParser\Node\Param;
1516
use PhpParser\Node\Stmt\ClassMethod;
@@ -76,6 +77,7 @@ public function checkFunction(
7677
string $templateTypeMissingInParameterMessage,
7778
string $unresolvableParameterTypeMessage,
7879
string $unresolvableReturnTypeMessage,
80+
string $noDiscardVoidReturnMessage,
7981
): array
8082
{
8183
return $this->checkParametersAcceptor(
@@ -88,23 +90,27 @@ public function checkFunction(
8890
$templateTypeMissingInParameterMessage,
8991
$unresolvableParameterTypeMessage,
9092
$unresolvableReturnTypeMessage,
93+
$noDiscardVoidReturnMessage,
9194
);
9295
}
9396

9497
/**
9598
* @param Node\Param[] $parameters
9699
* @param Node\Identifier|Node\Name|Node\ComplexType|null $returnTypeNode
100+
* @param Node\AttributeGroup[] $attribGroups
97101
* @return list<IdentifierRuleError>
98102
*/
99103
public function checkAnonymousFunction(
100104
Scope $scope,
101105
array $parameters,
102106
$returnTypeNode,
107+
array $attribGroups,
103108
string $parameterMessage,
104109
string $returnMessage,
105110
string $unionTypesMessage,
106111
string $unresolvableParameterTypeMessage,
107112
string $unresolvableReturnTypeMessage,
113+
string $noDiscardVoidReturnMessage,
108114
): array
109115
{
110116
$errors = [];
@@ -197,6 +203,19 @@ public function checkAnonymousFunction(
197203
if ($returnTypeNode === null) {
198204
return $errors;
199205
}
206+
if ($returnTypeNode instanceof FullyQualified && $returnTypeNode->name === 'void') {
207+
foreach ($attribGroupss as $attribGroup) {
208+
foreach ($attribGroup->attrs as $attrib) {
209+
if (strtolower($attrib->name) === 'nodiscard') {
210+
$errors[] = RuleErrorBuilder::message($noDiscardVoidReturnMessage)
211+
->line($returnTypeNode->getStartLine())
212+
->identifier('attribute.target')
213+
->build();
214+
break 2;
215+
}
216+
}
217+
}
218+
}
200219

201220
if (
202221
!$unionTypeReported
@@ -266,6 +285,7 @@ public function checkClassMethod(
266285
string $unresolvableParameterTypeMessage,
267286
string $unresolvableReturnTypeMessage,
268287
string $selfOutMessage,
288+
string $noDiscardVoidReturnMessage,
269289
): array
270290
{
271291
$errors = $this->checkParametersAcceptor(
@@ -278,6 +298,7 @@ public function checkClassMethod(
278298
$templateTypeMissingInParameterMessage,
279299
$unresolvableParameterTypeMessage,
280300
$unresolvableReturnTypeMessage,
301+
$noDiscardVoidReturnMessage,
281302
);
282303

283304
$selfOutType = $methodReflection->getSelfOutType();
@@ -329,6 +350,7 @@ private function checkParametersAcceptor(
329350
string $templateTypeMissingInParameterMessage,
330351
string $unresolvableParameterTypeMessage,
331352
string $unresolvableReturnTypeMessage,
353+
string $noDiscardVoidReturnMessage,
332354
): array
333355
{
334356
$errors = [];
@@ -473,6 +495,17 @@ private function checkParametersAcceptor(
473495
->build();
474496
}
475497
}
498+
if ($parametersAcceptor->hasNoDiscardAttribute()) {
499+
$returnType = $functionNode->getReturnType();
500+
if ($returnType instanceof FullyQualified
501+
&& $returnType->name === 'void'
502+
) {
503+
$errors[] = RuleErrorBuilder::message($noDiscardVoidReturnMessage)
504+
->line($returnTypeNode->getStartLine())
505+
->identifier('attribute.target')
506+
->build();
507+
}
508+
}
476509

477510
$returnTypeReferencedClasses = $this->getReturnTypeReferencedClasses($parametersAcceptor);
478511

src/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRule.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ public function processNode(Node $node, Scope $scope): array
4646
$scope,
4747
$node->getParams(),
4848
$node->getReturnType(),
49+
$node->getAttrGroups(),
4950
'Parameter $%s of anonymous function has invalid type %s.',
5051
'Anonymous function has invalid return type %s.',
5152
'Anonymous function uses native union types but they\'re supported only on PHP 8.0 and later.',
5253
'Parameter $%s of anonymous function has unresolvable native type.',
5354
'Anonymous function has unresolvable native return type.',
55+
'Attribute NoDiscard cannot be used on void anonymous function.',
5456
));
5557
}
5658

src/Rules/Functions/ExistingClassesInClosureTypehintsRule.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ public function processNode(Node $node, Scope $scope): array
3131
$scope,
3232
$node->getParams(),
3333
$node->getReturnType(),
34+
$node->getAttrGroups(),
3435
'Parameter $%s of anonymous function has invalid type %s.',
3536
'Anonymous function has invalid return type %s.',
3637
'Anonymous function uses native union types but they\'re supported only on PHP 8.0 and later.',
3738
'Parameter $%s of anonymous function has unresolvable native type.',
3839
'Anonymous function has unresolvable native return type.',
40+
'Attribute NoDiscard cannot be used on void anonymous function.',
3941
);
4042
}
4143

src/Rules/Functions/ExistingClassesInTypehintsRule.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public function processNode(Node $node, Scope $scope): array
5353
'Function %s() has unresolvable native return type.',
5454
$functionName,
5555
),
56+
sprintf(
57+
'Attribute NoDiscard cannot be used on void function %s().',
58+
$functionName
59+
),
5660
);
5761
}
5862

src/Rules/Methods/ExistingClassesInTypehintsRule.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ public function processNode(Node $node, Scope $scope): array
6464
$className,
6565
$methodName,
6666
),
67+
sprintf(
68+
'Attribute NoDiscard cannot be used on void method %s::%s().',
69+
$className,
70+
$methodName,
71+
),
6772
);
6873
}
6974

src/Rules/Properties/ExistingClassesInPropertyHookTypehintsRule.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ public function processNode(Node $node, Scope $scope): array
8484
$className,
8585
$propertyName,
8686
),
87+
sprintf(
88+
'Attribute NoDiscard cannot be used on void %s hook for property %s::$%s.',
89+
ucfirst($hookName),
90+
$className,
91+
$propertyName,
92+
),
8793
);
8894
}
8995

tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public function testRule(): void
5454
'Anonymous function has invalid return type ArrowFunctionExistingClassesInTypehints\Baz.',
5555
10,
5656
],
57+
[
58+
'Attribute NoDiscard cannot be used on void anonymous function.',
59+
12,
60+
],
5761
]);
5862
}
5963

@@ -324,4 +328,14 @@ public function testBug5206(): void
324328
$this->analyse([__DIR__ . '/data/bug-5206.php'], $errors);
325329
}
326330

331+
public function testNoDiscardVoid(): void
332+
{
333+
$this->analyse([__DIR__ . '/data/arrow-function-typehints-nodiscard.php'], [
334+
[
335+
'Attribute NoDiscard cannot be used on void anonymous function.',
336+
10,
337+
],
338+
]);
339+
}
340+
327341
}

tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,4 +353,14 @@ public function testDeprecatedImplicitlyNullableParameterType(): void
353353
]);
354354
}
355355

356+
public function testNoDiscardVoid(): void
357+
{
358+
$this->analyse([__DIR__ . '/data/closure-typehints-nodiscard.php'], [
359+
[
360+
'Attribute NoDiscard cannot be used on void anonymous function.',
361+
17,
362+
],
363+
]);
364+
}
365+
356366
}

tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,4 +489,14 @@ public function testParamClosureThisClasses(): void
489489
]);
490490
}
491491

492+
public function testNoDiscardVoid(): void
493+
{
494+
$this->analyse([__DIR__ . '/data/typehints-nodiscard.php'], [
495+
[
496+
'Attribute NoDiscard cannot be used on void function nothing().',
497+
6,
498+
],
499+
]);
500+
}
501+
492502
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace ArrowFunctionExistingClassesInTypehints;
4+
5+
class Demo
6+
{
7+
8+
public function doFoo()
9+
{
10+
#[\NoDiscard] fn(): void => true;
11+
}
12+
13+
}

0 commit comments

Comments
 (0)