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

ClassAliasStmtAppender   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 51.22%

Importance

Changes 0
Metric Value
dl 0
loc 93
ccs 21
cts 41
cp 0.5122
rs 10
c 0
b 0
f 0
wmc 14
lcom 2
cbo 9

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A afterTraverse() 0 14 3
A appendToNamespaceStmt() 0 10 1
B createNamespaceStmts() 0 29 8
A createAliasStmt() 0 17 1
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\Node\ClassAliasFuncCall;
18
use Humbug\PhpScoper\PhpParser\NodeVisitor\Resolver\FullyQualifiedNameResolver;
19
use Humbug\PhpScoper\Whitelist;
20
use PhpParser\Node;
21
use PhpParser\Node\Name\FullyQualified;
22
use PhpParser\Node\Stmt;
23
use PhpParser\Node\Stmt\Class_;
24
use PhpParser\Node\Stmt\Expression;
25
use PhpParser\Node\Stmt\Interface_;
26
use PhpParser\Node\Stmt\Namespace_;
27
use PhpParser\NodeVisitorAbstract;
28
use function array_reduce;
29
30
/**
31
 * Appends a `class_alias` to the whitelisted classes.
32
 *
33
 * ```
34
 * namespace A;
35
 *
36
 * class Foo
37
 * {
38
 * }
39
 * ```
40
 *
41
 * =>
42
 *
43
 * ```
44
 * namespace Humbug\A;
45
 *
46
 * class Foo
47
 * {
48
 * }
49
 *
50
 * class_alias('Humbug\A\Foo', 'A\Foo', false);
51
 * ```
52
 *
53
 * @internal
54
 */
55
final class ClassAliasStmtAppender extends NodeVisitorAbstract
56
{
57
    private $prefix;
58
    private $whitelist;
59
    private $nameResolver;
60
61 10
    public function __construct(string $prefix, Whitelist $whitelist, FullyQualifiedNameResolver $nameResolver)
62
    {
63 10
        $this->prefix = $prefix;
64 10
        $this->whitelist = $whitelist;
65 10
        $this->nameResolver = $nameResolver;
66
    }
67
68
    /**
69
     * @inheritdoc
70
     */
71 9
    public function afterTraverse(array $nodes): array
72
    {
73 9
        $newNodes = [];
74
75 9
        foreach ($nodes as $node) {
76 9
            if ($node instanceof Namespace_) {
77 9
                $node = $this->appendToNamespaceStmt($node);
78
            }
79
80 9
            $newNodes[] = $node;
81
        }
82
83 9
        return $newNodes;
84
    }
85
86 9
    private function appendToNamespaceStmt(Namespace_ $namespace): Namespace_
87
    {
88 9
        $namespace->stmts = array_reduce(
1 ignored issue
show
Documentation Bug introduced by
It seems like \array_reduce($namespace...espaceStmts'), array()) of type * is incompatible with the declared type array<integer,object<PhpParser\Node\Stmt>> of property $stmts.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
89 9
            $namespace->stmts,
90 9
            [$this, 'createNamespaceStmts'],
91 9
            []
92
        );
93
94 9
        return $namespace;
95
    }
96
97
    /**
98
     * @return Stmt[]
99
     */
100 9
    private function createNamespaceStmts(array $stmts, Stmt $stmt): array
101
    {
102 9
        $stmts[] = $stmt;
103
104 9
        if (false === ($stmt instanceof Class_ || $stmt instanceof Interface_)) {
105 9
            return $stmts;
106
        }
107
        /** @var Class_|Interface_ $stmt */
108
        if (null === $stmt->name) {
109
            return $stmts;
110
        }
111
112
        $originalName = $this->nameResolver->resolveName($stmt->name)->getName();
113
114
        if (false === ($originalName instanceof FullyQualified)
115
            || $this->whitelist->belongsToWhitelistedNamespace((string) $originalName)
116
            || (
117
                false === $this->whitelist->isSymbolWhitelisted((string) $originalName)
118
                && false === $this->whitelist->isGlobalWhitelistedClass((string) $originalName)
119
            )
120
        ) {
121
            return $stmts;
122
        }
123
        /* @var FullyQualified $originalName */
124
125
        $stmts[] = $this->createAliasStmt($originalName, $stmt);
126
127
        return $stmts;
128
    }
129
130
    private function createAliasStmt(FullyQualified $originalName, Node $stmt): Expression
131
    {
132
        $call = new ClassAliasFuncCall(
133
            FullyQualified::concat($this->prefix, $originalName),
134
            $originalName,
135
            $stmt->getAttributes()
136
        );
137
138
        $expression = new Expression(
139
            $call,
140
            $stmt->getAttributes()
141
        );
142
143
        $call->setAttribute(ParentNodeAppender::PARENT_ATTRIBUTE, $expression);
144
145
        return $expression;
146
    }
147
}
148