DefinitionVisitor   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 18.64%

Importance

Changes 0
Metric Value
dl 0
loc 125
ccs 11
cts 59
cp 0.1864
rs 10
c 0
b 0
f 0
wmc 24
lcom 1
cbo 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setFilePath() 0 4 1
A enterNode() 0 10 4
A prepareTrait() 0 14 2
A prepareFunction() 0 13 2
C prepareClass() 0 46 14
1
<?php
2
/**
3
 * @author Patsura Dmitry https://github.com/ovr <[email protected]>
4
 */
5
6
namespace PHPSA\Compiler;
7
8
use PhpParser\Node;
9
use PhpParser\NodeVisitorAbstract;
10
use PhpParser\Node\Stmt;
11
use PHPSA\Compiler;
12
use PHPSA\Definition\ClassDefinition;
13
use PHPSA\Definition\ClassMethod;
14
use PHPSA\Definition\FunctionDefinition;
15
use PHPSA\Definition\TraitDefinition;
16
17
class DefinitionVisitor extends NodeVisitorAbstract
18
{
19
    /**
20
     * @var Compiler
21
     */
22
    protected $compiler;
23
24
    /**
25
     * @var string|null
26
     */
27
    protected $filepath;
28
29 1
    public function __construct(Compiler $compiler)
30
    {
31 1
        $this->compiler = $compiler;
32 1
    }
33
34
    /**
35
     * @param Node $node
36
     * @return void
37
     */
38 1
    public function enterNode(Node $node)
39
    {
40 1
        if ($node instanceof Stmt\Class_) {
41
            $this->prepareClass($node);
42 1
        } elseif ($node instanceof Stmt\Function_) {
43
            $this->prepareFunction($node);
44 1
        } elseif ($node instanceof Stmt\Trait_) {
45
            $this->prepareTrait($node);
46
        }
47 1
    }
48
49
    /**
50
     * @param Stmt\Trait_ $statement
51
     */
52
    public function prepareTrait(Stmt\Trait_ $statement)
53
    {
54
        $definition = new TraitDefinition($statement->name, $statement);
0 ignored issues
show
Documentation introduced by
$statement->name is of type object<PhpParser\Node\Identifier>|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
55
        $definition->setFilepath($this->filepath);
56
57
        if (isset($statement->namespace)) {
58
            /** @var \PhpParser\Node\Name $namespace */
59
            $namespace = $statement->namespace;
60
            $definition->setNamespace($namespace->toString());
61
        }
62
63
        $definition->precompile();
64
        $this->compiler->addTrait($definition);
65
    }
66
67
    /**
68
     * @param Stmt\Function_ $statement
69
     */
70
    public function prepareFunction(Stmt\Function_ $statement)
71
    {
72
        $definition = new FunctionDefinition($statement->name, $statement);
73
        $definition->setFilepath($this->filepath);
74
75
        if (isset($statement->namespace)) {
76
            /** @var \PhpParser\Node\Name $namespace */
77
            $namespace = $statement->namespace;
78
            $definition->setNamespace($namespace->toString());
79
        }
80
81
        $this->compiler->addFunction($definition);
82
    }
83
84
    /**
85
     * @param Stmt\Class_ $statement
86
     */
87
    public function prepareClass(Stmt\Class_ $statement)
88
    {
89
        $definition = new ClassDefinition($statement->name, $statement, $statement->flags);
0 ignored issues
show
Documentation introduced by
$statement->name is of type object<PhpParser\Node\Identifier>|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
90
        $definition->setFilepath($this->filepath);
91
92
        if (isset($statement->namespace)) {
93
            /** @var \PhpParser\Node\Name $namespace */
94
            $namespace = $statement->namespace;
95
            $definition->setNamespace($namespace->toString());
96
        }
97
98
        if ($statement->extends) {
99
            $definition->setExtendsClass($statement->extends->toString());
100
        }
101
102
        if ($statement->implements) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $statement->implements of type PhpParser\Node\Name[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
103
            foreach ($statement->implements as $interface) {
104
                $definition->addInterface($interface->toString());
105
            }
106
        }
107
108
        foreach ($statement->stmts as $stmt) {
109
            if ($stmt instanceof Node\Stmt\ClassMethod) {
110
                $definition->addMethod(
111
                    new ClassMethod($stmt->name, $stmt, $stmt->flags)
112
                );
113
            } elseif ($stmt instanceof Node\Stmt\Property) {
114
                $definition->addProperty($stmt);
115
            } elseif ($stmt instanceof Node\Stmt\TraitUse) {
116
                foreach ($stmt->traits as $traitPart) {
117
                    $traitDefinition = $this->compiler->getTrait($traitPart->toString());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $traitDefinition is correct as $this->compiler->getTrait($traitPart->toString()) (which targets PHPSA\Compiler::getTrait()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
118
                    if (!$traitDefinition && $definition->getNamespace()) {
119
                        $traitDefinition = $this->compiler->getTrait($definition->getNamespace() . '\\' . $traitPart);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $traitDefinition is correct as $this->compiler->getTrai...() . '\\' . $traitPart) (which targets PHPSA\Compiler::getTrait()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
120
                    }
121
122
                    if ($traitDefinition) {
123
                        $definition->mergeTrait($traitDefinition, $stmt->adaptations);
124
                    }
125
                }
126
            } elseif ($stmt instanceof Node\Stmt\ClassConst) {
127
                $definition->addConst($stmt);
128
            }
129
        }
130
131
        $this->compiler->addClass($definition);
132
    }
133
134
    /**
135
     * @param string $filepath
136
     */
137 1
    public function setFilePath($filepath)
138
    {
139 1
        $this->filepath = $filepath;
140 1
    }
141
}
142