Passed
Push — master ( 6704cb...7d5ecd )
by Théo
03:14 queued 01:01
created

ParentNodeAppender   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 74
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 24
c 0
b 0
f 0
dl 0
loc 74
ccs 19
cts 19
cp 1
rs 10
wmc 13

7 Methods

Rating   Name   Duplication   Size   Complexity  
A findParent() 0 5 2
A getParent() 0 3 1
A leaveNode() 0 5 1
A setParent() 0 3 1
A beforeTraverse() 0 5 1
A enterNode() 0 28 6
A hasParent() 0 3 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 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