1<?php declare(strict_types=1);
2
3namespace PhpParser\NodeVisitor;
4
5use PhpParser\Node;
6use PhpParser\NodeVisitorAbstract;
7
8/**
9 * Visitor that connects a child node to its parent node
10 * as well as its sibling nodes.
11 *
12 * On the child node, the parent node can be accessed through
13 * <code>$node->getAttribute('parent')</code>, the previous
14 * node can be accessed through <code>$node->getAttribute('previous')</code>,
15 * and the next node can be accessed through <code>$node->getAttribute('next')</code>.
16 */
17final class NodeConnectingVisitor extends NodeVisitorAbstract {
18    /**
19     * @var Node[]
20     */
21    private array $stack = [];
22
23    /**
24     * @var ?Node
25     */
26    private $previous;
27
28    public function beforeTraverse(array $nodes) {
29        $this->stack    = [];
30        $this->previous = null;
31    }
32
33    public function enterNode(Node $node) {
34        if (!empty($this->stack)) {
35            $node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
36        }
37
38        if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) {
39            $node->setAttribute('previous', $this->previous);
40            $this->previous->setAttribute('next', $node);
41        }
42
43        $this->stack[] = $node;
44    }
45
46    public function leaveNode(Node $node) {
47        $this->previous = $node;
48
49        array_pop($this->stack);
50    }
51}
52