ACAV f0ba4b7c9529
Abstract Syntax Tree (AST) visualization tool for C, C++, and Objective-C
Loading...
Searching...
No Matches
SourceLocationIndex.cpp
1/*$!{
2* Aurora Clang AST Viewer (ACAV)
3*
4* Copyright (c) 2026 Min Liu
5* Copyright (c) 2026 Michael David Adams
6*
7* SPDX-License-Identifier: GPL-2.0-or-later
8*
9* This program is free software; you can redistribute it and/or modify
10* it under the terms of the GNU General Public License as published by
11* the Free Software Foundation; either version 2 of the License, or
12* (at your option) any later version.
13*
14* This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details.
18*
19* You should have received a copy of the GNU General Public License along
20* with this program; if not, see <https://www.gnu.org/licenses/>.
21}$!*/
22
24#include "core/AstNode.h"
25#include <algorithm>
26
27namespace acav {
28
29// ============================================================================
30// Interval Implementation
31// ============================================================================
32
33bool Interval::contains(unsigned line, unsigned column) const {
34 // Check if point is after or at begin
35 bool afterBegin = (line > beginLine) ||
36 (line == beginLine && column >= beginColumn);
37
38 // Check if point is before or at end
39 bool beforeEnd = (line < endLine) || (line == endLine && column <= endColumn);
40
41 return afterBegin && beforeEnd;
42}
43
44bool Interval::operator<(const Interval &other) const {
45 if (beginLine != other.beginLine) {
46 return beginLine < other.beginLine;
47 }
48 return beginColumn < other.beginColumn;
49}
50
51// ============================================================================
52// IntervalTree Implementation (using sorted vector)
53// ============================================================================
54
56 intervals_.push_back(interval);
57}
58
60 if (finalized_) {
61 return;
62 }
63
64 // Sort intervals by start position
65 std::sort(intervals_.begin(), intervals_.end());
66 finalized_ = true;
67}
68
69std::vector<AstViewNode *> IntervalTree::query(unsigned line,
70 unsigned column) const {
71 std::vector<AstViewNode *> results;
72
73 // Linear scan through intervals to find all matches
74 // This is O(n) but with good cache locality
75 // For most files, n is reasonable (<10k intervals)
76 for (const Interval &interval : intervals_) {
77 // Early exit optimization: if interval starts after query point, stop
78 if (interval.beginLine > line ||
79 (interval.beginLine == line && interval.beginColumn > column)) {
80 break;
81 }
82
83 // Check if interval contains the point
84 if (interval.contains(line, column)) {
85 results.push_back(interval.node);
86 }
87 }
88
89 // Sort by depth (deepest first = most specific)
90 std::sort(results.begin(), results.end(),
91 [this](AstViewNode *a, AstViewNode *b) {
92 return getDepth(a) > getDepth(b);
93 });
94
95 return results;
96}
97
99 unsigned beginColumn,
100 unsigned endLine,
101 unsigned endColumn) const {
102 // Find first interval starting at or after (beginLine, beginColumn)
103 Interval searchKey{beginLine, beginColumn, 0, 0, nullptr};
104 auto it = std::lower_bound(intervals_.begin(), intervals_.end(), searchKey);
105
106 for (; it != intervals_.end(); ++it) {
107 // Stop if interval starts after range end
108 if (it->beginLine > endLine ||
109 (it->beginLine == endLine && it->beginColumn > endColumn)) {
110 break;
111 }
112
113 // Check if interval is fully contained: start >= range start, end <= range end
114 bool startsInRange = it->beginLine > beginLine ||
115 (it->beginLine == beginLine && it->beginColumn >= beginColumn);
116 bool endsInRange = it->endLine < endLine ||
117 (it->endLine == endLine && it->endColumn <= endColumn);
118
119 if (startsInRange && endsInRange) {
120 return it->node;
121 }
122 }
123
124 return nullptr;
125}
126
127unsigned IntervalTree::getDepth(AstViewNode *node) const {
128 if (!node) {
129 return 0;
130 }
131
132 unsigned depth = 0;
133 AstViewNode *current = node;
134 while (current->getParent()) {
135 ++depth;
136 current = current->getParent();
137 }
138 return depth;
139}
140
141// ============================================================================
142// SourceLocationIndex Implementation
143// ============================================================================
144
146 if (!node) {
147 return;
148 }
149
150 const SourceRange &range = node->getSourceRange();
151 FileID fileId = range.begin().fileID();
152
153 // Skip invalid locations (compiler-generated nodes)
154 if (fileId == FileManager::InvalidFileID) {
155 return;
156 }
157
158 // Create interval
159 Interval interval{range.begin().line(), range.begin().column(),
160 range.end().line(), range.end().column(), node};
161
162 // Insert into appropriate tree (create if needed)
163 trees_[fileId].insert(interval);
164}
165
167 // Finalize all trees (sort intervals)
168 for (auto &[fileId, tree] : trees_) {
169 tree.finalize();
170 }
171}
172
173std::vector<AstViewNode *> SourceLocationIndex::getNodesAt(FileID fileId,
174 unsigned line,
175 unsigned column) const {
176 auto it = trees_.find(fileId);
177 if (it == trees_.end()) {
178 return {}; // No tree for this file
179 }
180
181 return it->second.query(line, column);
182}
183
185 FileID fileId, unsigned beginLine, unsigned beginColumn, unsigned endLine,
186 unsigned endColumn) const {
187 auto it = trees_.find(fileId);
188 if (it == trees_.end()) {
189 return nullptr;
190 }
191
192 return it->second.queryFirstContained(beginLine, beginColumn, endLine,
193 endColumn);
194}
195
197 std::size_t total = 0;
198 for (const auto &[fileId, tree] : trees_) {
199 total += tree.size();
200 }
201 return total;
202}
203
205 return trees_.find(fileId) != trees_.end();
206}
207
208} // namespace acav
AST data structures and memory management.
std::size_t FileID
Type-safe identifier for registered files. 0 is reserved for invalid.
Definition FileManager.h:38
Source-to-AST node lookup index.
Represents node in AST tree hierarchy.
Definition AstNode.h:195
const SourceRange & getSourceRange() const
Get source range (delegates to data node).
Definition AstNode.h:219
static constexpr FileID InvalidFileID
Reserved invalid FileID.
Definition FileManager.h:47
AstViewNode * queryFirstContained(unsigned beginLine, unsigned beginColumn, unsigned endLine, unsigned endColumn) const
Find first interval fully contained within a range.
void finalize()
Sort intervals by start position (call once after all inserts).
std::vector< AstViewNode * > query(unsigned line, unsigned column) const
Find all intervals containing a point.
void insert(Interval interval)
Add interval to collection (not sorted yet).
void finalize()
Finalize all interval trees (call after all nodes added).
void addNode(AstViewNode *node)
Add node to index.
std::vector< AstViewNode * > getNodesAt(FileID fileId, unsigned line, unsigned column) const
Query nodes at specific source position.
bool hasFile(FileID fileId) const
Check whether the current TU AST contains any indexed nodes for a file.
std::size_t getTotalIntervals() const
Get total number of intervals across all files.
AstViewNode * getFirstNodeContainedInRange(FileID fileId, unsigned beginLine, unsigned beginColumn, unsigned endLine, unsigned endColumn) const
Query first node fully contained within a range.
Represents a span of source code (begin to end).
Represents an interval in source code with associated AST node.
bool operator<(const Interval &other) const
Compare intervals by start position for sorting.
bool contains(unsigned line, unsigned column) const
Check if interval contains a point.