/** * @param Node|array|mixed $nodes * @param int $offset * @param (Comment|Node)[] $result * @param bool $rightAdjustment * * @return bool True iff anything in $nodes include offset. */ private function getNodeAtOffsetRecursive($nodes, $offset, array &$result, $rightAdjustment) { if ($nodes instanceof Node) { $comments = $nodes->getAttribute('comments', []); foreach ($comments as $comment) { if ($comment instanceof Comment\Doc) { $start = $comment->getFilePos(); $end = $start + strlen($comment->getText()); if ($start <= $offset && $end + $rightAdjustment > $offset) { $result[] = $nodes; $result[] = $comment; return true; } } } // Namespace node needs special handling as it can be a no-braces namespace // where offsets include only declaration and not the logically contained statements. $isNamespace = $nodes instanceof Node\Stmt\Namespace_; $inRange = $nodes->getAttribute('startFilePos') <= $offset && $nodes->getAttribute('endFilePos') + $rightAdjustment >= $offset; if ($isNamespace || $inRange) { $result[] = $nodes; foreach ($nodes->getSubNodeNames() as $subnode) { if ($this->getNodeAtOffsetRecursive($nodes->{$subnode}, $offset, $result, $rightAdjustment)) { return true; } } if ($inRange) { return true; } } } elseif (is_array($nodes)) { foreach ($nodes as $node) { if ($this->getNodeAtOffsetRecursive($node, $offset, $result, $rightAdjustment)) { return true; } } } return false; }