Passed
Push — master ( 3749c1...b0239f )
by Théo
02:58
created

NameStmtPrefixer::prefixName()   D

Complexity

Conditions 39
Paths 67

Size

Total Lines 101
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 54
CRAP Score 39.009

Importance

Changes 0
Metric Value
cc 39
eloc 57
nc 67
nop 1
dl 0
loc 101
ccs 54
cts 55
cp 0.9818
crap 39.009
rs 4.2039
c 0
b 0
f 0

How to fix   Long Method    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
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper\PhpParser\NodeVisitor;
16
17
use Humbug\PhpScoper\PhpParser\NodeVisitor\Resolver\FullyQualifiedNameResolver;
18
use Humbug\PhpScoper\Reflector;
19
use PhpParser\Node;
20
use PhpParser\Node\Expr\ClassConstFetch;
21
use PhpParser\Node\Expr\ConstFetch;
22
use PhpParser\Node\Expr\FuncCall;
23
use PhpParser\Node\Expr\Instanceof_;
24
use PhpParser\Node\Expr\New_;
25
use PhpParser\Node\Expr\StaticCall;
26
use PhpParser\Node\Expr\StaticPropertyFetch;
27
use PhpParser\Node\Name;
28
use PhpParser\Node\Name\FullyQualified;
29
use PhpParser\Node\NullableType;
30
use PhpParser\Node\Param;
31
use PhpParser\Node\Stmt\Catch_;
32
use PhpParser\Node\Stmt\Class_;
33
use PhpParser\Node\Stmt\ClassMethod;
34
use PhpParser\Node\Stmt\Function_;
35
use PhpParser\Node\Stmt\Interface_;
36
use PhpParser\NodeVisitorAbstract;
37
use function in_array;
38
39
/**
40
 * ```
41
 * new Foo\Bar();
42
 * ```.
43
 *
44
 * =>
45
 *
46
 * ```
47
 * new \Humbug\Foo\Bar();
48
 * ```
49
 *
50
 * @private
51
 */
52
final class NameStmtPrefixer extends NodeVisitorAbstract
53
{
54
    public const PHP_FUNCTION_KEYWORDS = [
55
        'self',
56
        'static',
57
        'parent',
58
    ];
59
60
    private $prefix;
61
    private $nameResolver;
62
    private $reflector;
63
64
    /**
65
     * @param string                     $prefix
66
     * @param FullyQualifiedNameResolver $nameResolver
67
     * @param Reflector                  $reflector
68
     */
69 422
    public function __construct(
70
        string $prefix,
71
        FullyQualifiedNameResolver $nameResolver,
72
        Reflector $reflector
73
    ) {
74 422
        $this->prefix = $prefix;
75 422
        $this->nameResolver = $nameResolver;
76 422
        $this->reflector = $reflector;
77
    }
78
79
    /**
80
     * @inheritdoc
81
     */
82 421
    public function enterNode(Node $node): Node
83
    {
84 421
        return ($node instanceof Name && AppendParentNode::hasParent($node))
85 419
            ? $this->prefixName($node)
86 421
            : $node
87
        ;
88
    }
89
90 419
    private function prefixName(Name $name): Node
91
    {
92 419
        $parentNode = AppendParentNode::getParent($name);
93
94 419
        if ($parentNode instanceof NullableType) {
95 4
            if (false === AppendParentNode::hasParent($parentNode)) {
96
                return $name;
97
            }
98
99 4
            $parentNode = AppendParentNode::getParent($parentNode);
100
        }
101
102
        if (false === (
103 419
                $parentNode instanceof ConstFetch
104 419
                || $parentNode instanceof ClassConstFetch
105 419
                || $parentNode instanceof StaticPropertyFetch
106 419
                || $parentNode instanceof Param
107 419
                || $parentNode instanceof FuncCall
108 419
                || $parentNode instanceof StaticCall
109 419
                || $parentNode instanceof Function_
110 419
                || $parentNode instanceof ClassMethod
111 419
                || $parentNode instanceof New_
112 419
                || $parentNode instanceof Class_
113 419
                || $parentNode instanceof Interface_
114 419
                || $parentNode instanceof Catch_
115 419
                || $parentNode instanceof Instanceof_
116
            )
117
        ) {
118 419
            return $name;
119
        }
120
121
        if (
122
            (
123 329
                $parentNode instanceof FuncCall
124 329
                || $parentNode instanceof StaticCall
125 329
                || $parentNode instanceof ClassConstFetch
126 329
                || $parentNode instanceof StaticPropertyFetch
127 329
                || $parentNode instanceof New_
128 329
                || $parentNode instanceof Param
129 329
                || $parentNode instanceof Catch_
130 329
                || $parentNode instanceof Instanceof_
131
            )
132 329
            && in_array((string) $name, self::PHP_FUNCTION_KEYWORDS, true)
133
        ) {
134 8
            return $name;
135
        }
136
137 327
        if ($parentNode instanceof ConstFetch && 'null' === (string) $name) {
138 2
            return $name;
139
        }
140
141 327
        $resolvedValue = $this->nameResolver->resolveName($name);
142
143 327
        $resolvedName = $resolvedValue->getName();
144
145
        // Skip if is already prefixed
146 327
        if ($this->prefix === $resolvedName->getFirst()) {
147 4
            return $resolvedName;
148
        }
149
150
        // Check if the class can be prefixed
151 327
        if (false === ($parentNode instanceof ConstFetch || $parentNode instanceof FuncCall)) {
152 240
            if ($this->reflector->isClassInternal($resolvedName->toString())) {
153 54
                return $resolvedName;
154
            }
155
        }
156
157
        // Constants have a fallback autoloading so we cannot prefix them when the name is ambiguous
158
        // See https://wiki.php.net/rfc/fallback-to-root-scope-deprecation
159 290
        if ($parentNode instanceof ConstFetch) {
160 109
            if ($this->reflector->isConstantInternal($resolvedName->toString())) {
161 75
                return new FullyQualified($resolvedName->toString(), $resolvedName->getAttributes());
162
            }
163
164 34
            if (false === ($resolvedName instanceof FullyQualified)) {
165 1
                return $resolvedName;
166
            }
167
        }
168
169
        // Functions have a fallback autoloading so we cannot prefix them when the name is ambiguous
170
        // See https://wiki.php.net/rfc/fallback-to-root-scope-deprecation
171 280
        if ($parentNode instanceof FuncCall) {
172 100
            if ($this->reflector->isFunctionInternal($resolvedName->toString())) {
173 67
                return new FullyQualified($resolvedName->toString(), $resolvedName->getAttributes());
174
            }
175
176 34
            if (false === ($resolvedName instanceof FullyQualified)) {
177 2
                return $resolvedName;
178
            }
179
        }
180
181 266
        if ('self' === (string) $resolvedName && $parentNode instanceof ClassMethod) {
182 3
            return $name;
183
        }
184
185 266
        return FullyQualified::concat(
186 266
            $this->prefix,
187 266
            $resolvedName->toString(),
188 266
            $resolvedName->getAttributes()
189
        );
190
    }
191
}
192