Passed
Pull Request — master (#506)
by Théo
02:22
created

ParentNodeAppender::enterNode()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 12
c 0
b 0
f 0
nc 7
nop 1
dl 0
loc 28
ccs 7
cts 7
cp 1
crap 6
rs 9.2222
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 PhpParser\Node;
18
use PhpParser\NodeVisitorAbstract;
19
use function array_pop;
20
use function count;
21
22
/**
23
 * Appends the parent node as an attribute to each node. This allows to have
24
 * more context in the other visitors when inspecting a node.
25
 *
26
 * @private
27
 */
28
final class ParentNodeAppender extends NodeVisitorAbstract
29
{
30
    private const PARENT_ATTRIBUTE = 'parent';
31
32
    /**
33
     * @var Node[]
34 547
     */
35
    private array $stack;
36 547
37
    public static function setParent(Node $node, Node $parent): void
38
    {
39 547
        $node->setAttribute(self::PARENT_ATTRIBUTE, $parent);
40
    }
41 547
42
    public static function hasParent(Node $node): bool
43
    {
44 454
        return $node->hasAttribute(self::PARENT_ATTRIBUTE);
45
    }
46 454
47 454
    public static function getParent(Node $node): Node
48 454
    {
49
        return $node->getAttribute(self::PARENT_ATTRIBUTE);
50
    }
51
52
    public static function findParent(Node $node): ?Node
53
    {
54
        return $node->hasAttribute(self::PARENT_ATTRIBUTE)
55 549
            ? $node->getAttribute(self::PARENT_ATTRIBUTE)
56
            : null
57 549
        ;
58
    }
59 549
60
    public function beforeTraverse(array $nodes): ?array
61
    {
62
        $this->stack = [];
63
64
        return $nodes;
65 548
    }
66
67 548
    public function enterNode(Node $node): Node
68 547
    {
69
        if ([] !== $this->stack) {
70
            self::setParent($node, $this->stack[count($this->stack) - 1]);
71 548
72
            // In some cases, e.g. to replace a node content, we need to access
73 548
            // the child nodes early (i.e. before NodeVisitor::enterNode()) in
74
            // which case without the following they cannot be accessed to
75
            // with their parent node
76
            if ($node instanceof Node\Stmt\Const_) {
77
                foreach ($node->consts as $const) {
78
                    self::setParent($const, $node);
79 548
                    self::setParent($const->name, $const);
80
                }
81 548
            }
82
83 548
            if ($node instanceof Node\Stmt\ClassLike) {
84
                $name = $node->name;
85
86
                if (null !== $name) {
87
                    self::setParent($name, $node);
88
                }
89
            }
90
        }
91
92
        $this->stack[] = $node;
93
94
        return $node;
95
    }
96
97
    public function leaveNode(Node $node): Node
98
    {
99
        array_pop($this->stack);
100
101
        return $node;
102
    }
103
}
104