1use super::graph_v2::{CodeEdgeV2, CodeGraphV2, MatchExprDataV2};
9use crate::symbol::{FileId, SymbolId, SymbolPath, SymbolRegistry};
10use crate::SymbolKind;
11
12pub struct GraphBuilderV2<'a> {
29 graph: CodeGraphV2,
30 registry: &'a mut SymbolRegistry,
31}
32
33impl<'a> GraphBuilderV2<'a> {
34 pub fn new(registry: &'a mut SymbolRegistry) -> Self {
36 Self {
37 graph: CodeGraphV2::new(),
38 registry,
39 }
40 }
41
42 pub fn with_capacity(registry: &'a mut SymbolRegistry, nodes: usize, edges: usize) -> Self {
44 Self {
45 graph: CodeGraphV2::with_capacity(nodes, edges),
46 registry,
47 }
48 }
49
50 pub fn add_symbol(
59 &mut self,
60 path: SymbolPath,
61 kind: SymbolKind,
62 ) -> Result<SymbolId, crate::symbol::RegistrationError> {
63 let id = self.registry.register(path, kind)?;
64 self.graph.add_node(id);
65 self.graph.add_to_kind_index(id, kind);
66 Ok(id)
67 }
68
69 pub fn add_existing_symbol(&mut self, id: SymbolId, kind: SymbolKind) {
73 self.graph.add_node(id);
74 self.graph.add_to_kind_index(id, kind);
75 }
76
77 pub fn add_crate_root(
79 &mut self,
80 path: SymbolPath,
81 ) -> Result<SymbolId, crate::symbol::RegistrationError> {
82 let id = self.registry.register(path, SymbolKind::Mod)?;
83 self.graph.add_crate_root(id);
84 self.graph.add_to_kind_index(id, SymbolKind::Mod);
85 Ok(id)
86 }
87
88 pub fn add_existing_crate_root(&mut self, id: SymbolId) {
90 self.graph.add_crate_root(id);
91 self.graph.add_to_kind_index(id, SymbolKind::Mod);
92 }
93
94 pub fn add_contains(&mut self, parent: SymbolId, child: SymbolId) {
100 self.graph.add_edge(parent, child, CodeEdgeV2::Contains);
101 }
102
103 pub fn add_call(&mut self, caller: SymbolId, callee: SymbolId) {
105 self.graph.add_edge(caller, callee, CodeEdgeV2::Calls);
106 }
107
108 pub fn add_implements(&mut self, implementor: SymbolId, trait_or_type: SymbolId) {
110 self.graph
111 .add_edge(implementor, trait_or_type, CodeEdgeV2::Implements);
112 }
113
114 pub fn add_match_expr(
130 &mut self,
131 function_id: SymbolId,
132 file_id: FileId,
133 enum_id: SymbolId,
134 offset: u32,
135 line: u32,
136 ) {
137 self.graph.add_match_expr(
138 function_id,
139 MatchExprDataV2 {
140 file_id,
141 enum_id,
142 offset,
143 line,
144 },
145 );
146 }
147
148 pub fn build(self) -> CodeGraphV2 {
157 self.graph
158 }
159
160 pub fn registry(&self) -> &SymbolRegistry {
162 self.registry
163 }
164
165 pub fn registry_mut(&mut self) -> &mut SymbolRegistry {
167 self.registry
168 }
169
170 pub fn graph(&self) -> &CodeGraphV2 {
172 &self.graph
173 }
174}
175
176#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_builder_basic() {
186 let mut registry = SymbolRegistry::new();
187 let mut builder = GraphBuilderV2::new(&mut registry);
188
189 let foo = builder
190 .add_symbol(
191 SymbolPath::parse("mylib::foo").unwrap(),
192 SymbolKind::Function,
193 )
194 .unwrap();
195 let bar = builder
196 .add_symbol(
197 SymbolPath::parse("mylib::bar").unwrap(),
198 SymbolKind::Function,
199 )
200 .unwrap();
201
202 builder.add_call(foo, bar);
203
204 let graph = builder.build();
205 assert_eq!(graph.node_count(), 2);
206 assert_eq!(graph.edge_count(), 1);
207 }
208
209 #[test]
210 fn test_builder_module_structure() {
211 let mut registry = SymbolRegistry::new();
212 let mut builder = GraphBuilderV2::new(&mut registry);
213
214 let crate_root = builder
215 .add_crate_root(SymbolPath::parse("mylib").unwrap())
216 .unwrap();
217 let module = builder
218 .add_symbol(
219 SymbolPath::parse("mylib::handlers").unwrap(),
220 SymbolKind::Mod,
221 )
222 .unwrap();
223 let func = builder
224 .add_symbol(
225 SymbolPath::parse("mylib::handlers::handle").unwrap(),
226 SymbolKind::Function,
227 )
228 .unwrap();
229
230 builder.add_contains(crate_root, module);
231 builder.add_contains(module, func);
232
233 let graph = builder.build();
234 let children: Vec<_> = graph.children_of(crate_root).collect();
235 assert_eq!(children.len(), 1);
236
237 let module_children: Vec<_> = graph.children_of(module).collect();
238 assert_eq!(module_children.len(), 1);
239
240 assert_eq!(graph.parent_of(func), Some(module));
241 }
242
243 #[test]
244 fn test_builder_kind_index() {
245 let mut registry = SymbolRegistry::new();
246 let mut builder = GraphBuilderV2::new(&mut registry);
247
248 builder
249 .add_symbol(SymbolPath::parse("mylib::Foo").unwrap(), SymbolKind::Struct)
250 .unwrap();
251 builder
252 .add_symbol(
253 SymbolPath::parse("mylib::bar").unwrap(),
254 SymbolKind::Function,
255 )
256 .unwrap();
257 builder
258 .add_symbol(
259 SymbolPath::parse("mylib::baz").unwrap(),
260 SymbolKind::Function,
261 )
262 .unwrap();
263
264 let graph = builder.build();
265
266 let structs: Vec<_> = graph.iter_by_kind(SymbolKind::Struct).collect();
267 assert_eq!(structs.len(), 1);
268
269 let functions: Vec<_> = graph.iter_by_kind(SymbolKind::Function).collect();
270 assert_eq!(functions.len(), 2);
271 }
272
273 #[test]
274 fn test_builder_with_capacity() {
275 let mut registry = SymbolRegistry::new();
276 let builder = GraphBuilderV2::with_capacity(&mut registry, 100, 200);
277 let graph = builder.build();
278 assert!(graph.is_empty());
279 }
280
281 #[test]
282 fn test_builder_callers_callees() {
283 let mut registry = SymbolRegistry::new();
284 let mut builder = GraphBuilderV2::new(&mut registry);
285
286 let main = builder
287 .add_symbol(
288 SymbolPath::parse("mylib::main").unwrap(),
289 SymbolKind::Function,
290 )
291 .unwrap();
292 let helper1 = builder
293 .add_symbol(
294 SymbolPath::parse("mylib::helper1").unwrap(),
295 SymbolKind::Function,
296 )
297 .unwrap();
298 let helper2 = builder
299 .add_symbol(
300 SymbolPath::parse("mylib::helper2").unwrap(),
301 SymbolKind::Function,
302 )
303 .unwrap();
304 let util = builder
305 .add_symbol(
306 SymbolPath::parse("mylib::util").unwrap(),
307 SymbolKind::Function,
308 )
309 .unwrap();
310
311 builder.add_call(main, helper1);
313 builder.add_call(main, helper2);
314 builder.add_call(helper1, util);
316 builder.add_call(helper2, util);
317
318 let graph = builder.build();
319
320 let main_callees: Vec<_> = graph.callees_of(main).collect();
322 assert_eq!(main_callees.len(), 2);
323
324 let util_callers: Vec<_> = graph.callers_of(util).collect();
326 assert_eq!(util_callers.len(), 2);
327 }
328
329 #[test]
330 fn test_builder_implements() {
331 let mut registry = SymbolRegistry::new();
332 let mut builder = GraphBuilderV2::new(&mut registry);
333
334 let trait_id = builder
335 .add_symbol(
336 SymbolPath::parse("mylib::MyTrait").unwrap(),
337 SymbolKind::Trait,
338 )
339 .unwrap();
340 let impl1 = builder
341 .add_symbol(SymbolPath::parse("mylib::Foo").unwrap(), SymbolKind::Struct)
342 .unwrap();
343 let impl2 = builder
344 .add_symbol(SymbolPath::parse("mylib::Bar").unwrap(), SymbolKind::Struct)
345 .unwrap();
346
347 builder.add_implements(impl1, trait_id);
348 builder.add_implements(impl2, trait_id);
349
350 let graph = builder.build();
351
352 let implementors: Vec<_> = graph.implementors_of(trait_id).collect();
353 assert_eq!(implementors.len(), 2);
354 }
355}