Completed
Push — master ( 243d41...5e59d9 )
by Théo
03:17
created

NameStmtPrefixer::prefixName()   D

Complexity

Conditions 34
Paths 27

Size

Total Lines 95
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 47
CRAP Score 34.0103

Importance

Changes 0
Metric Value
cc 34
eloc 53
nc 27
nop 1
dl 0
loc 95
ccs 47
cts 48
cp 0.9792
crap 34.0103
rs 4.3505
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\NodeVisitor;
16
17
use Humbug\PhpScoper\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\New_;
24
use PhpParser\Node\Expr\StaticCall;
25
use PhpParser\Node\Name;
26
use PhpParser\Node\Name\FullyQualified;
27
use PhpParser\Node\NullableType;
28
use PhpParser\Node\Param;
29
use PhpParser\Node\Stmt\Catch_;
30
use PhpParser\Node\Stmt\Class_;
31
use PhpParser\Node\Stmt\ClassMethod;
32
use PhpParser\Node\Stmt\Function_;
33
use PhpParser\Node\Stmt\Interface_;
34
use PhpParser\NodeVisitorAbstract;
35
36
/**
37
 * ```
38
 * new Foo\Bar();
39
 * ```.
40
 *
41
 * =>
42
 *
43
 * ```
44
 * new \Humbug\Foo\Bar();
45
 * ```
46
 *
47
 * @private
48
 */
49
final class NameStmtPrefixer extends NodeVisitorAbstract
50
{
51
    public const PHP_FUNCTION_KEYWORDS = [
52
        'self',
53
        'static',
54
        'parent',
55
    ];
56
57
    private $prefix;
58
    private $nameResolver;
59
    private $reflector;
60
61
    /**
62
     * @param string                     $prefix
63
     * @param FullyQualifiedNameResolver $nameResolver
64
     * @param Reflector                  $reflector
65
     */
66 359
    public function __construct(
67
        string $prefix,
68
        FullyQualifiedNameResolver $nameResolver,
69
        Reflector $reflector
70
    ) {
71 359
        $this->prefix = $prefix;
72 359
        $this->nameResolver = $nameResolver;
73 359
        $this->reflector = $reflector;
74
    }
75
76
    /**
77
     * @inheritdoc
78
     */
79 358
    public function enterNode(Node $node): Node
80
    {
81 358
        return ($node instanceof Name && AppendParentNode::hasParent($node))
82 356
            ? $this->prefixName($node)
83 358
            : $node
84
        ;
85
    }
86
87 356
    private function prefixName(Name $name): Node
88
    {
89 356
        $parentNode = AppendParentNode::getParent($name);
90
91 356
        if ($parentNode instanceof NullableType) {
92 4
            if (false === AppendParentNode::hasParent($parentNode)) {
93
                return $name;
94
            }
95
96 4
            $parentNode = AppendParentNode::getParent($parentNode);
97
        }
98
99
        if (false === (
100 356
                $parentNode instanceof ConstFetch
101 356
                || $parentNode instanceof ClassConstFetch
102 356
                || $parentNode instanceof Param
103 356
                || $parentNode instanceof FuncCall
104 356
                || $parentNode instanceof StaticCall
105 356
                || $parentNode instanceof Function_
106 356
                || $parentNode instanceof ClassMethod
107 356
                || $parentNode instanceof New_
108 356
                || $parentNode instanceof Class_
109 356
                || $parentNode instanceof Interface_
110 356
                || $parentNode instanceof Catch_
111
            )
112
        ) {
113 356
            return $name;
114
        }
115
116
        if (
117
            (
118 265
                $parentNode instanceof FuncCall
119 265
                || $parentNode instanceof StaticCall
120 265
                || $parentNode instanceof ClassConstFetch
121 265
                || $parentNode instanceof New_
122 265
                || $parentNode instanceof Param
123
            )
124 265
            && in_array((string) $name, self::PHP_FUNCTION_KEYWORDS, true)
125
        ) {
126 6
            return $name;
127
        }
128
129 265
        if ($parentNode instanceof ConstFetch && 'null' === (string) $name) {
130 2
            return $name;
131
        }
132
133 265
        $resolvedValue = $this->nameResolver->resolveName($name);
134
135 265
        $resolvedName = $resolvedValue->getName();
136
137
        // Skip if is already prefixed
138 265
        if ($this->prefix === $resolvedName->getFirst()) {
139 4
            return $resolvedName;
140
        }
141
142
        // Check if the class can be prefixed
143 265
        if (false === ($parentNode instanceof ConstFetch || $parentNode instanceof FuncCall)) {
144 182
            if ($this->reflector->isClassInternal($resolvedName->toString())) {
145 41
                return $resolvedName;
146
            }
147
        }
148
149 241
        if ($parentNode instanceof ConstFetch
150
            && (
151 97
                $this->reflector->isConstantInternal($resolvedName->toString())
152
                // Constants have a fallback autoloading so we cannot prefix them when the name is ambiguous
153
                // See https://wiki.php.net/rfc/fallback-to-root-scope-deprecation
154 241
                || false === ($resolvedName instanceof FullyQualified)
155
            )
156
        ) {
157 65
            return $resolvedName;
158
        }
159
160
        if (
161 232
            $parentNode instanceof FuncCall
162
            && (
163 88
                $this->reflector->isFunctionInternal($resolvedName->toString())
164
                // Functions have a fallback autoloading so we cannot prefix them when the name is ambiguous
165
                // See https://wiki.php.net/rfc/fallback-to-root-scope-deprecation
166 232
                || false === ($resolvedName instanceof FullyQualified)
167
            )
168
        ) {
169 58
            return $resolvedName;
170
        }
171
172 219
        if ('self' === (string) $resolvedName && $parentNode instanceof ClassMethod) {
173 3
            return $name;
174
        }
175
176 219
        return FullyQualified::concat(
177 219
            $this->prefix,
178 219
            $resolvedName->toString(),
179 219
            $resolvedName->getAttributes()
180
        );
181
    }
182
}
183