Completed
Pull Request — master (#463)
by Alexander
30:17 queued 05:15
created

SelfValueVisitor::enterNode()   C

Complexity

Conditions 14
Paths 10

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 14

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 20
cts 20
cp 1
rs 6.2666
c 0
b 0
f 0
cc 14
nc 10
nop 1
crap 14

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
/*
5
 * Go! AOP framework
6
 *
7
 * @copyright Copyright 2018, Lisachenko Alexander <[email protected]>
8
 *
9
 * This source file is subject to the license that is bundled
10
 * with this source code in the file LICENSE.
11
 */
12
13
namespace Go\Instrument\Transformer;
14
15
use PhpParser\Node;
16
use PhpParser\Node\Expr\ClassConstFetch;
17
use PhpParser\Node\Expr\Closure;
18
use PhpParser\Node\Expr\Instanceof_;
19
use PhpParser\Node\Expr\New_;
20
use PhpParser\Node\Expr\StaticCall;
21
use PhpParser\Node\Name;
22
use PhpParser\Node\Name\FullyQualified;
23
use PhpParser\Node\NullableType;
24
use PhpParser\Node\Param;
25
use PhpParser\Node\Stmt\Catch_;
26
use PhpParser\Node\Stmt\Class_;
27
use PhpParser\Node\Stmt\ClassMethod;
28
use PhpParser\Node\Stmt\Namespace_;
29
use PhpParser\NodeVisitorAbstract;
30
31
/**
32
 * Node visitor that resolves class name for `self` nodes with FQN
33
 */
34
final class SelfValueVisitor extends NodeVisitorAbstract
35
{
36
    /**
37
     * List of replaced nodes
38
     *
39
     * @var Node[]
40
     */
41
    protected array $replacedNodes = [];
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_ARRAY, expecting T_FUNCTION or T_CONST
Loading history...
42
43
    /**
44
     * Current namespace
45
     */
46
    protected ?string $namespace = null;
47
48
    /**
49
     * Current class name
50
     */
51
    protected ?Name $className = null;
52 2
53
    /**
54 2
     * Returns list of changed `self` nodes
55
     *
56
     * @return Node[]
57
     */
58
    public function getReplacedNodes(): array
59
    {
60 2
        return $this->replacedNodes;
61
    }
62 2
63 2
    /**
64 2
     * @inheritDoc
65 2
     */
66
    public function beforeTraverse(array $nodes)
67
    {
68
        $this->namespace     = null;
69
        $this->className     = null;
70 2
        $this->replacedNodes = [];
71
    }
72 2
73 2
    /**
74 2
     * @inheritDoc
75 2
     */
76 2
    public function enterNode(Node $node)
77
    {
78 2
        if ($node instanceof Namespace_) {
79 2
            $this->namespace = $node->name->toString();
80 2
        } elseif ($node instanceof Class_) {
81 2
            if ($node->name !== null) {
82
                $this->className = new Name($node->name->toString());
83 2
            }
84 2
        } elseif ($node instanceof ClassMethod || $node instanceof Closure) {
85 2
            $node->returnType = $this->resolveType($node->returnType);
86 2
        } elseif ($node instanceof Param) {
87
            $node->type = $this->resolveType($node->type);
88 2
        } elseif (
89 2
            $node instanceof StaticCall
90
            || $node instanceof ClassConstFetch
91 2
            || $node instanceof New_
92 1
            || $node instanceof Instanceof_
93 1
        ) {
94
            if ($node->class instanceof Name) {
95
                $node->class = $this->resolveClassName($node->class);
96 2
            }
97
        } elseif ($node instanceof Catch_) {
98
            foreach ($node->types as &$type) {
99
                $type = $this->resolveClassName($type);
100
            }
101
        }
102
    }
103
104
    /**
105 2
     * Resolves `self` class name with value
106
     *
107
     * @param Name $name Instance of original node
108 2
     *
109 1
     * @return Name|FullyQualified
110
     */
111
    protected function resolveClassName(Name $name): Name
112
    {
113 1
        // Skip all names except special `self`
114 1
        if (strtolower($name->toString()) !== 'self') {
115 1
            return $name;
116
        }
117 1
118 1
        // Save the original name
119
        $originalName = $name;
120 1
        $name = clone $originalName;
121
        $name->setAttribute('originalName', $originalName);
122 1
123
        $fullClassName    = Name::concat($this->namespace, $this->className);
124
        $resolvedSelfName = new FullyQualified('\\' . ltrim($fullClassName->toString(), '\\'), $name->getAttributes());
125
126
        $this->replacedNodes[] = $resolvedSelfName;
127
128
        return $resolvedSelfName;
129
    }
130
131
    /**
132 2
     * Helper method for resolving type nodes
133
     *
134 2
     * @param Node|string|null $node Instance of node
135
     *
136
     * @return Node|Name|FullyQualified
137
     */
138 2
    private function resolveType($node)
139 2
    {
140
        if ($node instanceof NullableType) {
141
            $node->type = $this->resolveType($node->type);
142 2
            return $node;
143
        }
144
        if ($node instanceof Name) {
145
            return $this->resolveClassName($node);
146
        }
147
148
        return $node;
149
    }
150
}
151