Passed
Push — trunk ( 37af04...c71cc1 )
by Christian
13:15 queued 12s
created

FinalClassRule   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 49
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 17
dl 0
loc 49
rs 10
c 1
b 0
f 0
wmc 9

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getNodeType() 0 3 1
A isMessageHandler() 0 16 4
A processNode() 0 19 4
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\DevOps\StaticAnalyze\PHPStan\Rules;
4
5
use PhpParser\Node;
6
use PHPStan\Analyser\Scope;
0 ignored issues
show
Bug introduced by
The type PHPStan\Analyser\Scope was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use PHPStan\Node\InClassNode;
0 ignored issues
show
Bug introduced by
The type PHPStan\Node\InClassNode was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use PHPStan\Rules\Rule;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\Rule was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use PHPStan\Rules\RuleError;
0 ignored issues
show
Bug introduced by
The type PHPStan\Rules\RuleError was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
11
12
/**
13
 * @package core
14
 * @implements Rule<InClassNode>
15
 *
16
 * @internal
17
 */
18
class FinalClassRule implements Rule
19
{
20
    public function getNodeType(): string
21
    {
22
        return InClassNode::class;
23
    }
24
25
    /**
26
     * @param InClassNode $node
27
     *
28
     * @return array<array-key, RuleError|string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, RuleError|string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, RuleError|string>.
Loading history...
29
     */
30
    public function processNode(Node $node, Scope $scope): array
31
    {
32
        if ($node->getClassReflection()->isFinal()) {
0 ignored issues
show
Bug introduced by
The method getClassReflection() does not exist on PhpParser\Node. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
        if ($node->/** @scrutinizer ignore-call */ getClassReflection()->isFinal()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
33
            return [];
34
        }
35
36
        if ($this->isMessageHandler($node)) {
37
            $classDeprecation = $node->getClassReflection()->getDeprecatedDescription() ?? '';
38
            /**
39
             * @deprecated tag:v6.5.0 - remove deprecation check, as all message handlers become final in v6.5.0
40
             */
41
            if (\str_contains($classDeprecation, 'tag:v6.5.0')) {
42
                return [];
43
            }
44
45
            return ['MessageHandlers must be final, so they cannot be extended/overwritten.'];
46
        }
47
48
        return [];
49
    }
50
51
    private function isMessageHandler(InClassNode $node): bool
52
    {
53
        $class = $node->getClassReflection();
54
55
        if ($class->isAbstract()) {
56
            // abstract base classes should not be final
57
            return false;
58
        }
59
60
        foreach ($class->getInterfaces() as $interface) {
61
            if ($interface->getName() === MessageHandlerInterface::class) {
62
                return true;
63
            }
64
        }
65
66
        return false;
67
    }
68
}
69