Passed
Pull Request — master (#40)
by Alexander
09:55 queued 07:23
created

ParserVisitor::getClassNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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\NodeTraverser;
10
use PhpParser\NodeVisitorAbstract;
11
12
/**
13
 * @internal for ParserClassifier
14
 */
15
final class ParserVisitor extends NodeVisitorAbstract
16
{
17
    /**
18
     * @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...
19
     */
20
    private array $classNames = [];
21
22
    /**
23
     * @psalm-param class-string $allowedParentClass
24
     */
25 11
    public function __construct(
26
        private array $allowedInterfaces,
27
        private array $allowedAttributes,
28
        private ?string $allowedParentClass = null
29
    ) {
30 11
    }
31
32 11
    public function enterNode(Node $node)
33
    {
34 11
        if (!($node instanceof Class_)) {
35 11
            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...
36
        }
37
38 11
        if (!$this->skipClass($node)) {
39
            /**
40
             * @var class-string $className
41
             * @psalm-suppress PossiblyNullReference checked in {@see skipClass} method.
42
             */
43 11
            $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

43
            /** @scrutinizer ignore-call */ 
44
            $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...
44 11
            $this->classNames[] = $className;
45
        }
46
47 11
        return NodeTraverser::DONT_TRAVERSE_CHILDREN;
48
    }
49
50
    /**
51
     * @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...
52
     */
53 11
    public function getClassNames(): array
54
    {
55 11
        return $this->classNames;
56
    }
57
58 11
    private function skipClass(Class_ $class): bool
59
    {
60 11
        if ($class->namespacedName === null || $class->isAnonymous()) {
61 7
            return true;
62
        }
63 11
        $className = $class->namespacedName->toString();
64 11
        $interfacesNames = class_implements($className);
65
        if (
66 11
            $interfacesNames !== false &&
67 11
            count(array_intersect($this->allowedInterfaces, $interfacesNames)) !== count($this->allowedInterfaces)
68
        ) {
69 5
            return true;
70
        }
71 11
        $attributesNames = [];
72 11
        foreach ($class->attrGroups as $attrGroup) {
73 5
            foreach ($attrGroup->attrs as $attr) {
74 5
                $attributesNames[] = $attr->name->toString();
75
            }
76
        }
77 11
        if (count(array_intersect($this->allowedAttributes, $attributesNames)) !== count($this->allowedAttributes)) {
78 2
            return true;
79
        }
80
81 11
        $classParents = class_parents($className);
82
83 11
        return ($this->allowedParentClass !== null && $classParents !== false) &&
84 11
            !in_array($this->allowedParentClass, $classParents, true);
85
    }
86
}
87