Passed
Pull Request — master (#38)
by Rustam
02:30
created

ParserVisitor::enterNode()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 12
ccs 5
cts 5
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Classifier;
6
7
use PhpParser\Node;
8
use PhpParser\Node\Stmt\Class_;
9
use PhpParser\NodeVisitorAbstract;
10
11
/**
12
 * @internal for ParserClassifier
13
 */
14
final class ParserVisitor extends NodeVisitorAbstract
15
{
16
    /**
17
     * @var array<class-string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string>.
Loading history...
18
     */
19
    private array $classNames = [];
20
21
    /**
22
     * @psalm-param class-string $allowedParentClass
23
     */
24 10
    public function __construct(
25
        private array $allowedInterfaces,
26
        private array $allowedAttributes,
27
        private ?string $allowedParentClass = null
28
    ) {
29 10
    }
30
31 10
    public function enterNode(Node $node)
32
    {
33 10
        if (($node instanceof Class_) && !$this->skipClass($node)) {
34
            /**
35
             * @var class-string $className
36
             * @psalm-suppress PossiblyNullReference checked in {@see skipClass} method.
37
             */
38 10
            $className = $node->namespacedName->toString();
0 ignored issues
show
Bug introduced by
The method toString() does not exist on null. ( Ignorable by Annotation )

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

38
            /** @scrutinizer ignore-call */ 
39
            $className = $node->namespacedName->toString();

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...
39 10
            $this->classNames[] = $className;
40
        }
41
42 10
        return parent::enterNode($node);
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::enterNode($node) targeting PhpParser\NodeVisitorAbstract::enterNode() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
43
    }
44
45
    /**
46
     * @return array<class-string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string>.
Loading history...
47
     */
48 10
    public function getClassNames(): array
49
    {
50 10
        return $this->classNames;
51
    }
52
53 10
    private function skipClass(Class_ $class): bool
54
    {
55 10
        if ($class->namespacedName === null || $class->isAnonymous()) {
56 7
            return true;
57
        }
58 10
        $className = $class->namespacedName->toString();
59 10
        $interfacesNames = class_implements($className);
60
        if (
61 10
            $interfacesNames !== false &&
62 10
            count(array_intersect($this->allowedInterfaces, $interfacesNames)) !== count($this->allowedInterfaces)
63
        ) {
64 5
            return true;
65
        }
66 10
        $attributesNames = [];
67 10
        foreach ($class->attrGroups as $attrGroup) {
68 5
            foreach ($attrGroup->attrs as $attr) {
69 5
                $attributesNames[] = $attr->name->toString();
70
            }
71
        }
72 10
        if (count(array_intersect($this->allowedAttributes, $attributesNames)) !== count($this->allowedAttributes)) {
73 2
            return true;
74
        }
75
76 10
        $classParents = class_parents($className);
77
78 10
        return ($this->allowedParentClass !== null && $classParents !== false) &&
79 10
            !in_array($this->allowedParentClass, $classParents, true);
80
    }
81
}
82