Completed
Push — master ( b2e2db...3e3691 )
by Théo
04:39 queued 02:20
created

UseStmtPrefixer::shouldPrefixUseStmt()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 8.0231

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 8
nop 1
dl 0
loc 31
ccs 13
cts 14
cp 0.9286
crap 8.0231
rs 5.3846
c 0
b 0
f 0
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\UseStmt;
16
17
use Humbug\PhpScoper\NodeVisitor\AppendParentNode;
18
use Humbug\PhpScoper\Reflector;
19
use PhpParser\Node;
20
use PhpParser\Node\Name;
21
use PhpParser\Node\Stmt\Use_;
22
use PhpParser\Node\Stmt\UseUse;
23
use PhpParser\NodeVisitorAbstract;
24
25
/**
26
 * Prefixes the use statements.
27
 */
28
final class UseStmtPrefixer extends NodeVisitorAbstract
29
{
30
    private $prefix;
31
    private $whitelist;
32
    private $reflector;
33
34
    /**
35
     * @param string    $prefix
36
     * @param string[]  $whitelist
37
     * @param Reflector $reflector
38
     */
39 342
    public function __construct(string $prefix, array $whitelist, Reflector $reflector)
40
    {
41 342
        $this->prefix = $prefix;
42 342
        $this->whitelist = $whitelist;
43 342
        $this->reflector = $reflector;
44
    }
45
46
    /**
47
     * @inheritdoc
48
     */
49 341
    public function enterNode(Node $node)
50
    {
51 341
        if ($node instanceof UseUse && $this->shouldPrefixUseStmt($node)) {
52 148
            $node->name = Name::concat($this->prefix, $node->name);
53
        }
54
55 341
        return $node;
56
    }
57
58 196
    private function shouldPrefixUseStmt(UseUse $use): bool
59
    {
60 196
        $useType = $this->findUseType($use);
61
62
        // If is already from the prefix namespace
63 196
        if ($this->prefix === $use->name->getFirst()) {
64 11
            return false;
65
        }
66
67
        // Is not from the Composer namespace
68 185
        if ('Composer' === $use->name->getFirst()) {
69
            return false;
70
        }
71
72 185
        if (1 === count($use->name->parts)) {
73 135
            if (Use_::TYPE_FUNCTION === $useType) {
74 11
                return false === $this->reflector->isFunctionInternal($use->name->getFirst());
75
            }
76
77 124
            if (Use_::TYPE_CONSTANT === $useType) {
78 11
                return false === $this->reflector->isConstantInternal($use->name->getFirst());
79
            }
80
81 113
            return Use_::TYPE_NORMAL !== $useType || false === $this->reflector->isClassInternal($use->name->getFirst());
82
        }
83
84
        return false === (
85 54
            Use_::TYPE_NORMAL === $useType
86 54
            && in_array((string) $use->name, $this->whitelist)
87
        );
88
    }
89
90
    /**
91
     * Finds the type of the use statement.
92
     *
93
     * @param UseUse $use
94
     *
95
     * @return int See \PhpParser\Node\Stmt\Use_ type constants.
96
     */
97 196
    private function findUseType(UseUse $use): int
98
    {
99 196
        if (Use_::TYPE_UNKNOWN === $use->type) {
100
            /** @var Use_ $parentNode */
101 191
            $parentNode = AppendParentNode::getParent($use);
102
103 191
            return $parentNode->type;
104
        }
105
106 5
        return $use->type;
107
    }
108
}
109