Completed
Push — master ( 0647fd...b9e92e )
by Théo
27:07 queued 08:01
created

UseStmtCollection::isFunctionName()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
nc 5
nop 2
dl 0
loc 17
ccs 8
cts 8
cp 1
crap 6
rs 9.0777
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\PhpParser\NodeVisitor\Collection;
16
17
use ArrayIterator;
18
use Humbug\PhpScoper\PhpParser\Node\NamedIdentifier;
19
use Humbug\PhpScoper\PhpParser\NodeVisitor\ParentNodeAppender;
20
use IteratorAggregate;
21
use PhpParser\Node;
22
use PhpParser\Node\Expr\ConstFetch;
23
use PhpParser\Node\Expr\FuncCall;
24
use PhpParser\Node\Name;
25
use PhpParser\Node\Stmt\ClassLike;
26
use PhpParser\Node\Stmt\Function_;
27
use PhpParser\Node\Stmt\Use_;
28
use PhpParser\Node\Stmt\UseUse;
29
use function count;
30
use function Humbug\PhpScoper\clone_node;
31
32
/**
33
 * Utility class collecting all the use statements for the scoped files allowing to easily find the use which a node
34
 * may use.
35
 *
36
 * @private
37
 */
38
final class UseStmtCollection implements IteratorAggregate
39
{
40
    /**
41
     * @var Use_[][]
42
     */
43
    private $nodes = [
44
        null => [],
45
    ];
46
47 264
    public function add(?Name $namespaceName, Use_ $node): void
48
    {
49 264
        $this->nodes[(string) $namespaceName][] = clone_node($node);
50
    }
51
52
    /**
53
     * Finds the statements matching the given name.
54
     *
55
     * $name = 'Foo';
56
     *
57
     * use X;
58
     * use Bar\Foo;
59
     * use Y;
60
     *
61
     * will return the use statement for `Bar\Foo`.
62
     *
63
     * @param Name|null $namespaceName
64
     * @param Name      $node
65
     *
66
     * @return null|Name
67
     */
68 427
    public function findStatementForNode(?Name $namespaceName, Name $node): ?Name
69
    {
70 427
        $name = strtolower($node->getFirst());
71
72 427
        $parentNode = ParentNodeAppender::findParent($node);
73
74 427
        if ($parentNode instanceof ClassLike
75 427
            && $node instanceof NamedIdentifier
76 427
            && $node->getOriginalNode() === $parentNode->name
77
        ) {
78
            // The current node can either be the class like name or one of its elements, e.g. extends or implements.
79
            // In the first case, the node was original an Identifier.
80
81 292
            return null;
82
        }
83
84 290
        $useStatements = $this->nodes[(string) $namespaceName] ?? [];
85
86 290
        foreach ($useStatements as $use_) {
87 131
            foreach ($use_->uses as $useStatement) {
88 131
                if (!($useStatement instanceof UseUse)) {
89
                    continue;
90
                }
91
92 131
                if ($name === $useStatement->getAlias()->toLowerString()) {
93 130
                    if ($this->isFunctionName($node, $parentNode)) {
94 12
                        if (Use_::TYPE_FUNCTION === $use_->type) {
95 7
                            return $useStatement->name;
96
                        }
97
98 5
                        continue;
99
                    }
100
101 122
                    if ($parentNode instanceof ConstFetch && 1 === count($node->parts)) {
102 13
                        if (Use_::TYPE_CONSTANT === $use_->type) {
103 11
                            return $useStatement->name;
104
                        }
105
106 3
                        continue;
107
                    }
108
109
                    // Match the alias
110 110
                    return $useStatement->name;
111
                }
112
113 19
                if (null !== $useStatement->alias) {
114 22
                    continue;
115
                }
116
            }
117
        }
118
119 187
        return null;
120
    }
121
122
    /**
123
     * @inheritdoc
124
     */
125
    public function getIterator(): iterable
126
    {
127
        return new ArrayIterator($this->nodes);
128
    }
129
130 130
    private function isFunctionName(Name $node, ?Node $parentNode): bool
131
    {
132 130
        if (null === $parentNode || 1 !== count($node->parts)) {
133 49
            return false;
134
        }
135
136 86
        if ($parentNode instanceof FuncCall) {
137 8
            return true;
138
        }
139
140 78
        if (false === ($parentNode instanceof Function_)) {
141 78
            return false;
142
        }
143
        /* @var Function_ $parentNode */
144
145 4
        return $node instanceof NamedIdentifier && $node->getOriginalNode() === $parentNode->name;
146
    }
147
}
148