Skip to content

Commit d206fb4

Browse files
authored
Remove custom virtual node FunctionEnd (#115)
1 parent 54e00b5 commit d206fb4

File tree

3 files changed

+71
-63
lines changed

3 files changed

+71
-63
lines changed

src/Node/FunctionEnd.php

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/Rules/ThrowsPhpDocRule.php

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Pepakriz\PHPStanExceptionRules\CheckedExceptionService;
1010
use Pepakriz\PHPStanExceptionRules\DefaultThrowTypeService;
1111
use Pepakriz\PHPStanExceptionRules\DynamicThrowTypeService;
12-
use Pepakriz\PHPStanExceptionRules\Node\FunctionEnd;
1312
use Pepakriz\PHPStanExceptionRules\Node\TryCatchTryEnd;
1413
use Pepakriz\PHPStanExceptionRules\ThrowsAnnotationReader;
1514
use Pepakriz\PHPStanExceptionRules\UnsupportedClassException;
@@ -32,10 +31,14 @@
3231
use PHPStan\Broker\Broker;
3332
use PHPStan\Broker\ClassNotFoundException;
3433
use PHPStan\Broker\FunctionNotFoundException;
34+
use PHPStan\Node\FunctionReturnStatementsNode;
35+
use PHPStan\Node\MethodReturnStatementsNode;
3536
use PHPStan\Node\UnreachableStatementNode;
3637
use PHPStan\Reflection\MethodReflection;
3738
use PHPStan\Reflection\MissingMethodFromReflectionException;
3839
use PHPStan\Rules\Rule;
40+
use PHPStan\Rules\RuleError;
41+
use PHPStan\Rules\RuleErrorBuilder;
3942
use PHPStan\ShouldNotHappenException;
4043
use PHPStan\Type\NeverType;
4144
use PHPStan\Type\ObjectType;
@@ -157,7 +160,7 @@ public function getNodeType(): string
157160
}
158161

159162
/**
160-
* @return string[]
163+
* @return RuleError[]
161164
*/
162165
public function processNode(Node $node, Scope $scope): array
163166
{
@@ -171,12 +174,16 @@ public function processNode(Node $node, Scope $scope): array
171174

172175
$method = $scope->getFunction();
173176
$isMethodWhitelisted = $method instanceof MethodReflection && $this->isWhitelistedMethod($method);
174-
if ($node instanceof FunctionEnd) {
177+
if ($node instanceof MethodReturnStatementsNode) {
175178
if ($isMethodWhitelisted && $method instanceof MethodReflection) {
176-
return $this->processWhitelistedMethod($method);
179+
return $this->processWhitelistedMethod($method, $node->getStartLine());
177180
}
178181

179-
return $this->processFunctionEnd($scope);
182+
return $this->processFunctionEnd($scope, $node->getStartLine());
183+
}
184+
185+
if ($node instanceof FunctionReturnStatementsNode) {
186+
return $this->processFunctionEnd($scope, $node->getStartLine());
180187
}
181188

182189
if ($isMethodWhitelisted) {
@@ -243,9 +250,9 @@ public function processNode(Node $node, Scope $scope): array
243250
}
244251

245252
/**
246-
* @return string[]
253+
* @return RuleError[]
247254
*/
248-
private function processWhitelistedMethod(MethodReflection $methodReflection): array
255+
private function processWhitelistedMethod(MethodReflection $methodReflection, int $startLine): array
249256
{
250257
$throwType = $methodReflection->getThrowType();
251258

@@ -254,8 +261,10 @@ private function processWhitelistedMethod(MethodReflection $methodReflection): a
254261
}
255262

256263
return array_map(
257-
static function (string $throwClass): string {
258-
return sprintf('Unused @throws %s annotation', $throwClass);
264+
static function (string $throwClass) use ($startLine): RuleError {
265+
return RuleErrorBuilder::message(sprintf('Unused @throws %s annotation', $throwClass))
266+
->line($startLine)
267+
->build();
259268
},
260269
TypeUtils::getDirectClassNames($throwType)
261270
);
@@ -279,7 +288,7 @@ private function isWhitelistedMethod(MethodReflection $methodReflection): bool
279288
}
280289

281290
/**
282-
* @return string[]
291+
* @return RuleError[]
283292
*/
284293
private function processTryCatch(TryCatch $node): array
285294
{
@@ -294,7 +303,7 @@ private function processTryCatch(TryCatch $node): array
294303
}
295304

296305
/**
297-
* @return string[]
306+
* @return RuleError[]
298307
*/
299308
private function processTryCatchTryEnd(): array
300309
{
@@ -304,7 +313,7 @@ private function processTryCatchTryEnd(): array
304313
}
305314

306315
/**
307-
* @return string[]
316+
* @return RuleError[]
308317
*/
309318
private function processThrow(Throw_ $node, Scope $scope): array
310319
{
@@ -314,7 +323,7 @@ private function processThrow(Throw_ $node, Scope $scope): array
314323
}
315324

316325
/**
317-
* @return string[]
326+
* @return RuleError[]
318327
*/
319328
private function processMethodCall(MethodCall $node, Scope $scope): array
320329
{
@@ -360,7 +369,7 @@ private function processMethodCall(MethodCall $node, Scope $scope): array
360369
}
361370

362371
/**
363-
* @return string[]
372+
* @return RuleError[]
364373
*/
365374
private function processStaticCall(StaticCall $node, Scope $scope): array
366375
{
@@ -397,7 +406,7 @@ private function processStaticCall(StaticCall $node, Scope $scope): array
397406
}
398407

399408
/**
400-
* @return string[]
409+
* @return RuleError[]
401410
*/
402411
private function processNew(New_ $node, Scope $scope): array
403412
{
@@ -420,7 +429,7 @@ private function processNew(New_ $node, Scope $scope): array
420429
}
421430

422431
/**
423-
* @return string[]
432+
* @return RuleError[]
424433
*/
425434
private function processExprTraversing(Expr $expr, Scope $scope, bool $useKey): array
426435
{
@@ -454,7 +463,7 @@ private function processExprTraversing(Expr $expr, Scope $scope, bool $useKey):
454463
}
455464

456465
/**
457-
* @return string[]
466+
* @return RuleError[]
458467
*/
459468
private function processFunction(Node\FunctionLike $node, Scope $scope): array
460469
{
@@ -492,19 +501,15 @@ private function processFunction(Node\FunctionLike $node, Scope $scope): array
492501

493502
if (!$node->hasAttribute(self::ATTRIBUTE_HAS_CLASS_METHOD_END)) {
494503
$node->setAttribute(self::ATTRIBUTE_HAS_CLASS_METHOD_END, true);
495-
if ($node->stmts === null) {
496-
throw new ShouldNotHappenException();
497-
}
498-
$node->stmts[] = new FunctionEnd($node);
499504
}
500505

501506
return [];
502507
}
503508

504509
/**
505-
* @return string[]
510+
* @return RuleError[]
506511
*/
507-
private function processFunctionEnd(Scope $scope): array
512+
private function processFunctionEnd(Scope $scope, int $startLine): array
508513
{
509514
$usedThrowsAnnotations = $this->throwsScope->exitFromThrowsAnnotationBlock();
510515

@@ -528,7 +533,9 @@ private function processFunctionEnd(Scope $scope): array
528533

529534
$messages = [];
530535
foreach ($unusedThrows as $unusedClass) {
531-
$messages[] = sprintf('Unused @throws %s annotation', $unusedClass);
536+
$messages[] = RuleErrorBuilder::message(sprintf('Unused @throws %s annotation', $unusedClass))
537+
->line($startLine)
538+
->build();
532539
}
533540

534541
return $messages;
@@ -603,7 +610,7 @@ private function isImplementation(ReflectionMethod $reflection): bool
603610
}
604611

605612
/**
606-
* @return string[]
613+
* @return RuleError[]
607614
*/
608615
private function processCatch(Catch_ $node): array
609616
{
@@ -623,11 +630,11 @@ private function processCatch(Catch_ $node): array
623630

624631
if (!$this->checkedExceptionService->isCheckedException($type->toString())) {
625632
foreach ($caughtChecked as $caughtCheckedException) {
626-
$messages[] = sprintf(
633+
$messages[] = RuleErrorBuilder::message(sprintf(
627634
'Catching checked exception %s as unchecked %s is not supported properly in this moment. Eliminate checked exceptions by custom catch statement.',
628635
$caughtCheckedException,
629636
$type->toString()
630-
);
637+
))->build();
631638
}
632639
}
633640

@@ -647,14 +654,14 @@ private function processCatch(Catch_ $node): array
647654
continue;
648655
}
649656

650-
$messages[] = sprintf('%s is never thrown in the corresponding try block', $exceptionClass);
657+
$messages[] = RuleErrorBuilder::message(sprintf('%s is never thrown in the corresponding try block', $exceptionClass))->build();
651658
}
652659

653660
return $messages;
654661
}
655662

656663
/**
657-
* @return string[]
664+
* @return RuleError[]
658665
*/
659666
private function processFuncCall(FuncCall $node, Scope $scope): array
660667
{
@@ -699,7 +706,7 @@ private function processFuncCall(FuncCall $node, Scope $scope): array
699706
}
700707

701708
/**
702-
* @return string[]
709+
* @return RuleError[]
703710
*/
704711
private function processDiv(Expr $divisor, Scope $scope): array
705712
{
@@ -725,7 +732,7 @@ private function processDiv(Expr $divisor, Scope $scope): array
725732
}
726733

727734
/**
728-
* @return string[]
735+
* @return RuleError[]
729736
*/
730737
private function processShift(Expr $value, Scope $scope): array
731738
{
@@ -774,7 +781,7 @@ private function getThrowTypesOnMethod($class, array $methods, Scope $scope): ar
774781
/**
775782
* @param Name|Expr|ClassLike $class
776783
* @param string[] $methods
777-
* @return string[]
784+
* @return RuleError[]
778785
*/
779786
private function processThrowTypesOnMethod($class, array $methods, Scope $scope): array
780787
{
@@ -784,7 +791,7 @@ private function processThrowTypesOnMethod($class, array $methods, Scope $scope)
784791
}
785792

786793
/**
787-
* @return string[]
794+
* @return RuleError[]
788795
*/
789796
private function processThrowsTypes(Type $targetThrowType): array
790797
{
@@ -797,12 +804,12 @@ private function processThrowsTypes(Type $targetThrowType): array
797804
return [];
798805
}
799806

800-
return array_map(static function (string $exceptionClassName) use ($isInGlobalScope): string {
807+
return array_map(static function (string $exceptionClassName) use ($isInGlobalScope): RuleError {
801808
if ($isInGlobalScope) {
802-
return sprintf('Throwing checked exception %s in global scope is prohibited', $exceptionClassName);
809+
return RuleErrorBuilder::message(sprintf('Throwing checked exception %s in global scope is prohibited', $exceptionClassName))->build();
803810
}
804811

805-
return sprintf('Missing @throws %s annotation', $exceptionClassName);
812+
return RuleErrorBuilder::message(sprintf('Missing @throws %s annotation', $exceptionClassName))->build();
806813
}, $targetExceptionClasses);
807814
}
808815

tests/src/Rules/data/try-catch.php

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use LogicException;
66
use RuntimeException;
77
use Throwable;
8+
use function rand;
89

910
class FooRuntimeException extends RuntimeException {}
1011
class BarRuntimeException extends RuntimeException {}
@@ -131,9 +132,15 @@ public function caughtSomeSubtypesAndConcreteException(): void
131132
*/
132133
private function throwUnion(): void
133134
{
134-
throw new FooRuntimeException();
135-
throw new BarRuntimeException();
136-
throw new SomeRuntimeException();
135+
if (rand(0, 1)) {
136+
throw new FooRuntimeException();
137+
}
138+
if (rand(0, 1)) {
139+
throw new BarRuntimeException();
140+
}
141+
if (rand(0, 1)) {
142+
throw new SomeRuntimeException();
143+
}
137144
}
138145

139146
/**
@@ -143,19 +150,31 @@ private function throwUnion(): void
143150
*/
144151
private static function throwStaticUnion(): void
145152
{
146-
throw new FooRuntimeException();
147-
throw new BarRuntimeException();
148-
throw new SomeRuntimeException();
153+
if (rand(0, 1)) {
154+
throw new FooRuntimeException();
155+
}
156+
if (rand(0, 1)) {
157+
throw new BarRuntimeException();
158+
}
159+
if (rand(0, 1)) {
160+
throw new SomeRuntimeException();
161+
}
149162
}
150163

151164
/**
152165
* @throws RuntimeException
153166
*/
154167
private function throwAsParent(): void
155168
{
156-
throw new FooRuntimeException();
157-
throw new BarRuntimeException();
158-
throw new SomeRuntimeException();
169+
if (rand(0, 1)) {
170+
throw new FooRuntimeException();
171+
}
172+
if (rand(0, 1)) {
173+
throw new BarRuntimeException();
174+
}
175+
if (rand(0, 1)) {
176+
throw new SomeRuntimeException();
177+
}
159178
}
160179

161180
}

0 commit comments

Comments
 (0)