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

ClassAliasStmtAppender::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
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;
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 548
    public function __construct(string $prefix, Whitelist $whitelist, FullyQualifiedNameResolver $nameResolver)
62
    {
63 548
        $this->prefix = $prefix;
64 548
        $this->whitelist = $whitelist;
65 548
        $this->nameResolver = $nameResolver;
66
    }
67
68
    /**
69
     * @inheritdoc
70
     */
71 547
    public function afterTraverse(array $nodes): array
72
    {
73 547
        $newNodes = [];
74
75 547
        foreach ($nodes as $node) {
76 546
            if ($node instanceof Namespace_) {
77 544
                $node = $this->appendToNamespaceStmt($node);
78
            }
79
80 546
            $newNodes[] = $node;
81
        }
82
83 547
        return $newNodes;
84
    }
85
86 544
    private function appendToNamespaceStmt(Namespace_ $namespace): Namespace_
87
    {
88 544
        $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 544
            $namespace->stmts,
90 544
            [$this, 'createNamespaceStmts'],
91 544
            []
92
        );
93
94 544
        return $namespace;
95
    }
96
97
    /**
98
     * @return Stmt[]
99
     */
100 531
    private function createNamespaceStmts(array $stmts, Stmt $stmt): array
101
    {
102 531
        $stmts[] = $stmt;
103
104 531
        if (false === ($stmt instanceof Class_ || $stmt instanceof Interface_)) {
105 485
            return $stmts;
106
        }
107
        /** @var Class_|Interface_ $stmt */
108 287
        if (null === $stmt->name) {
109
            return $stmts;
110
        }
111
112 287
        $originalName = $this->nameResolver->resolveName($stmt->name)->getName();
113
114 287
        if (false === ($originalName instanceof FullyQualified)
115 287
            || $this->whitelist->belongsToWhitelistedNamespace((string) $originalName)
116
            || (
117 273
                false === $this->whitelist->isSymbolWhitelisted((string) $originalName)
118 287
                && false === $this->whitelist->isGlobalWhitelistedClass((string) $originalName)
119
            )
120
        ) {
121 253
            return $stmts;
122
        }
123
        /* @var FullyQualified $originalName */
124
125 77
        $stmts[] = $this->createAliasStmt($originalName, $stmt);
126
127 77
        return $stmts;
128
    }
129
130 77
    private function createAliasStmt(FullyQualified $originalName, Node $stmt): Expression
131
    {
132 77
        $call = new ClassAliasFuncCall(
133 77
            FullyQualified::concat($this->prefix, $originalName),
134 77
            $originalName,
135 77
            $stmt->getAttributes()
136
        );
137
138 77
        $expression = new Expression(
139 77
            $call,
140 77
            $stmt->getAttributes()
141
        );
142
143 77
        $call->setAttribute(ParentNodeAppender::PARENT_ATTRIBUTE, $expression);
144
145 77
        return $expression;
146
    }
147
}
148