Completed
Push — master ( 550011...0647fd )
by Théo
16:20 queued 07:57
created

FullyQualifiedNameResolver::resolveName()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0582

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 1
dl 0
loc 24
ccs 11
cts 13
cp 0.8462
crap 4.0582
rs 9.536
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\Resolver;
16
17
use Humbug\PhpScoper\PhpParser\Node\NamedIdentifier;
18
use Humbug\PhpScoper\PhpParser\NodeVisitor\Collection\NamespaceStmtCollection;
19
use Humbug\PhpScoper\PhpParser\NodeVisitor\Collection\UseStmtCollection;
20
use Humbug\PhpScoper\PhpParser\NodeVisitor\NameStmtPrefixer;
21
use Humbug\PhpScoper\PhpParser\NodeVisitor\ParentNodeAppender;
22
use PhpParser\Node;
23
use PhpParser\Node\Expr\ConstFetch;
24
use PhpParser\Node\Expr\FuncCall;
25
use PhpParser\Node\Identifier;
26
use PhpParser\Node\Name;
27
use PhpParser\Node\Name\FullyQualified;
28
use PhpParser\Node\Scalar\String_;
29
use function in_array;
30
use function ltrim;
31
32
/**
33
 * Attempts to resolve the node name into a fully qualified node. Returns a valid (non fully-qualified) name node on
34
 * failure.
35
 *
36
 * @private
37
 */
38
final class FullyQualifiedNameResolver
39
{
40
    private $namespaceStatements;
41
    private $useStatements;
42
43 10
    public function __construct(NamespaceStmtCollection $namespaceStatements, UseStmtCollection $useStatements)
44
    {
45 10
        $this->namespaceStatements = $namespaceStatements;
46 10
        $this->useStatements = $useStatements;
47
    }
48
49
    /**
50
     * @param Name|String_|Identifier $node
51
     */
52 7
    public function resolveName(Node $node): ResolvedValue
53
    {
54 7
        if ($node instanceof FullyQualified) {
55 6
            return new ResolvedValue($node, null, null);
56
        }
57
58 7
        if ($node instanceof String_) {
59
            return $this->resolveStringName($node);
60
        }
61
62 7
        if ($node instanceof Identifier) {
63
            $node = NamedIdentifier::create($node);
64
        }
65
66 7
        $namespaceName = $this->namespaceStatements->findNamespaceForNode($node);
67
68 7
        $useName = $this->useStatements->findStatementForNode($namespaceName, $node);
1 ignored issue
show
Bug introduced by
It seems like $node defined by parameter $node on line 52 can also be of type object<PhpParser\Node>; however, Humbug\PhpScoper\PhpPars...:findStatementForNode() does only seem to accept object<PhpParser\Node\Name>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
69
70 7
        return new ResolvedValue(
71 7
            $this->resolveNodeName($node, $namespaceName, $useName),
1 ignored issue
show
Bug introduced by
It seems like $node defined by parameter $node on line 52 can also be of type object<PhpParser\Node>; however, Humbug\PhpScoper\PhpPars...lver::resolveNodeName() does only seem to accept object<PhpParser\Node\Name>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
72 7
            $namespaceName,
73 7
            $useName
74
        );
75
    }
76
77 7
    private function resolveNodeName(Name $name, ?Name $namespace, ?Name $use): Name
78
    {
79 7
        if (null !== $use) {
80
            return FullyQualified::concat($use, $name->slice(1), $name->getAttributes());
81
        }
82
83 7
        if (null === $namespace) {
84 4
            return new FullyQualified($name, $name->getAttributes());
85
        }
86
87 3
        if (in_array((string) $name, NameStmtPrefixer::PHP_FUNCTION_KEYWORDS, true)) {
88
            return $name;
89
        }
90
91 3
        $parentNode = ParentNodeAppender::getParent($name);
92
93
        if (
94 3
            ($parentNode instanceof ConstFetch || $parentNode instanceof FuncCall)
95 3
            && 1 === count($name->parts)
96
        ) {
97
            // Ambiguous name, cannot determine the FQ name
98 3
            return $name;
99
        }
100
101 3
        return FullyQualified::concat($namespace, $name, $name->getAttributes());
102
    }
103
104
    private function resolveStringName(String_ $node): ResolvedValue
105
    {
106
        $name = new FullyQualified(ltrim($node->value, '\\'));
107
108
        $deducedNamespaceName = $name->slice(0, -1);
109
        $namespaceName = null;
110
111
        if (null !== $deducedNamespaceName) {
112
            $namespaceName = $this->namespaceStatements->findNamespaceByName($deducedNamespaceName->toString());
113
        }
114
115
        return new ResolvedValue(
116
            $name,
117
            $namespaceName,
118
            null
119
        );
120
    }
121
}
122