1use std::collections::HashMap;
85
86use rucc_base::Symbol;
87use rucc_ir::{AliasKind, Datum, Extra, Func, FuncId, Inst, Linkage, Module, Opcode, Pic};
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
94pub struct Node(u32);
95
96impl Node {
97 #[must_use]
99 pub const fn index(self) -> usize {
100 self.0 as usize
101 }
102}
103
104#[derive(Debug, Clone)]
106struct Entry {
107 name: Symbol,
109 func: Option<FuncId>,
112 body: Option<FuncId>,
114 calls: Vec<Node>,
116 unknown: bool,
118 address_taken: bool,
120}
121
122#[derive(Debug, Clone, Default)]
127pub struct CallGraph {
128 entries: Vec<Entry>,
130 by_name: HashMap<Symbol, Node>,
132 components: Vec<Vec<Node>>,
134 component_of: Vec<u32>,
136}
137
138impl CallGraph {
139 #[must_use]
144 pub fn of(module: &Module, pic: Pic) -> Self {
145 let mut graph = Self::default();
146 for id in module.funcs() {
147 let func = &module[id];
148 let body = (!func.is_declaration() && trusted(func, pic)).then_some(id);
149 let node = graph.intern(func.name);
150 let at = node.index();
151 graph.entries[at].func = Some(id);
152 graph.entries[at].body = body;
153 graph.entries[at].unknown = body.is_none();
156 }
157 for id in module.aliases() {
160 let alias = &module[id];
161 let node = graph.intern(alias.name);
162 match alias.kind {
163 AliasKind::Alias => {
166 let to = graph.intern(alias.target);
167 graph.entries[node.index()].calls.push(to);
168 }
171 AliasKind::IFunc => {
175 graph.entries[node.index()].unknown = true;
176 let resolver = graph.intern(alias.target);
177 graph.entries[resolver.index()].address_taken = true;
178 }
179 }
180 }
181 for id in module.funcs() {
184 let func = &module[id];
185 if func.is_declaration() {
186 continue;
187 }
188 let from = graph.by_name[&func.name];
189 for block in func.blocks() {
190 for inst in func.insts(block) {
191 graph.read(func, inst, from);
192 }
193 }
194 }
195 for id in module.globals() {
198 let init = module[id].init.map(|list| &module[list]).unwrap_or_default();
199 for datum in init {
200 if let Datum::Addr(reloc) | Datum::Away(reloc) = *datum {
201 graph.took_the_address_of(module[reloc].symbol);
202 }
203 }
204 }
205 graph.condense();
206 graph
207 }
208
209 pub fn nodes(&self) -> impl Iterator<Item = Node> + use<> {
211 (0..self.entries.len() as u32).map(Node)
212 }
213
214 #[must_use]
216 pub fn len(&self) -> usize {
217 self.entries.len()
218 }
219
220 #[must_use]
222 pub fn is_empty(&self) -> bool {
223 self.entries.is_empty()
224 }
225
226 #[must_use]
228 pub fn node(&self, name: Symbol) -> Option<Node> {
229 self.by_name.get(&name).copied()
230 }
231
232 #[must_use]
234 pub fn name(&self, node: Node) -> Symbol {
235 self.entries[node.index()].name
236 }
237
238 #[must_use]
244 pub fn func(&self, node: Node) -> Option<FuncId> {
245 self.entries[node.index()].func
246 }
247
248 #[must_use]
256 pub fn trusted_body(&self, node: Node) -> Option<FuncId> {
257 self.entries[node.index()].body
258 }
259
260 #[must_use]
262 pub fn calls(&self, node: Node) -> &[Node] {
263 &self.entries[node.index()].calls
264 }
265
266 #[must_use]
273 pub fn reaches_unknown(&self, node: Node) -> bool {
274 self.entries[node.index()].unknown
275 }
276
277 #[must_use]
288 pub fn address_taken(&self, node: Node) -> bool {
289 self.entries[node.index()].address_taken
290 }
291
292 #[must_use]
299 pub fn components(&self) -> &[Vec<Node>] {
300 &self.components
301 }
302
303 #[must_use]
305 pub fn component_of(&self, node: Node) -> usize {
306 self.component_of[node.index()] as usize
307 }
308
309 pub fn solve<T, S, F>(&self, start: S, mut transfer: F) -> Vec<T>
332 where
333 T: Clone + PartialEq,
334 S: Fn(Node) -> T,
335 F: FnMut(Node, &[T]) -> T,
336 {
337 let mut answers: Vec<T> = self.nodes().map(&start).collect();
338 for part in &self.components {
339 if let [only] = part[..] {
340 if !self.entries[only.index()].calls.contains(&only) {
341 answers[only.index()] = transfer(only, &answers);
342 continue;
343 }
344 }
345 let ceiling = 1000 + part.len() * 64;
350 let mut rounds = 0usize;
351 loop {
352 let mut settled = true;
353 for &node in part {
354 let now = transfer(node, &answers);
355 if now != answers[node.index()] {
356 answers[node.index()] = now;
357 settled = false;
358 }
359 }
360 if settled {
361 break;
362 }
363 rounds += 1;
364 debug_assert!(rounds < ceiling, "the transfer function is not monotone");
365 }
366 }
367 answers
368 }
369
370 fn intern(&mut self, name: Symbol) -> Node {
372 if let Some(&node) = self.by_name.get(&name) {
373 return node;
374 }
375 let node = Node(self.entries.len() as u32);
376 self.entries.push(Entry {
380 name,
381 func: None,
382 body: None,
383 calls: Vec::new(),
384 unknown: true,
385 address_taken: false,
386 });
387 self.by_name.insert(name, node);
388 node
389 }
390
391 fn took_the_address_of(&mut self, name: Symbol) {
402 if let Some(&node) = self.by_name.get(&name) {
403 self.entries[node.index()].address_taken = true;
404 }
405 }
406
407 fn read(&mut self, func: &Func, inst: Inst, from: Node) {
409 let data = &func[inst];
410 match data.opcode {
411 Opcode::Call | Opcode::TailCall => {
412 let name = match data.extra {
413 Extra::Call(at) => func[at].callee,
414 _ => None,
415 };
416 let Some(name) = name else {
419 self.entries[from.index()].unknown = true;
420 return;
421 };
422 let to = self.intern(name);
423 let calls = &mut self.entries[from.index()].calls;
424 if !calls.contains(&to) {
425 calls.push(to);
426 }
427 }
428 Opcode::CallIndirect | Opcode::Apply => self.entries[from.index()].unknown = true,
432 Opcode::InlineAsm | Opcode::TargetIntrinsic => {
436 self.entries[from.index()].unknown = true;
437 }
438 Opcode::GlobalAddr => {
440 if let Extra::Symbol(name) = data.extra {
441 self.took_the_address_of(name);
442 }
443 }
444 _ => {}
445 }
446 }
447
448 fn condense(&mut self) {
454 let count = self.entries.len();
455 let mut index = vec![u32::MAX; count];
458 let mut low = vec![0u32; count];
459 let mut on_stack = vec![false; count];
460 let mut stack: Vec<u32> = Vec::new();
461 let mut frames: Vec<(u32, usize)> = Vec::new();
462 let mut next = 0u32;
463 self.component_of = vec![u32::MAX; count];
464 for root in 0..count as u32 {
465 if index[root as usize] != u32::MAX {
466 continue;
467 }
468 index[root as usize] = next;
469 low[root as usize] = next;
470 next += 1;
471 stack.push(root);
472 on_stack[root as usize] = true;
473 frames.push((root, 0));
474 while let Some(&(node, at)) = frames.last() {
475 let edges = &self.entries[node as usize].calls;
476 if at < edges.len() {
477 let to = edges[at].0;
478 frames.last_mut().expect("the frame just read").1 += 1;
479 if index[to as usize] == u32::MAX {
480 index[to as usize] = next;
481 low[to as usize] = next;
482 next += 1;
483 stack.push(to);
484 on_stack[to as usize] = true;
485 frames.push((to, 0));
486 } else if on_stack[to as usize] {
487 low[node as usize] = low[node as usize].min(index[to as usize]);
488 }
489 continue;
490 }
491 frames.pop();
492 if low[node as usize] == index[node as usize] {
493 let mut part = Vec::new();
494 while let Some(top) = stack.pop() {
495 on_stack[top as usize] = false;
496 part.push(Node(top));
497 if top == node {
498 break;
499 }
500 }
501 part.sort_unstable();
502 let which = self.components.len() as u32;
503 for member in &part {
504 self.component_of[member.index()] = which;
505 }
506 self.components.push(part);
507 }
508 if let Some(&(above, _)) = frames.last() {
509 low[above as usize] = low[above as usize].min(low[node as usize]);
510 }
511 }
512 }
513 debug_assert!(
514 self.component_of.iter().all(|&which| which != u32::MAX),
515 "every node is in a component"
516 );
517 }
518}
519
520fn trusted(func: &Func, pic: Pic) -> bool {
530 !matches!(func.linkage, Linkage::Weak | Linkage::Common)
531 && !pic.replaceable(func.linkage, func.visibility)
532}
533
534#[cfg(test)]
535mod tests {
536 use rucc_base::Interner;
537 use rucc_ir::{
538 Alias, AliasKind, AsmInfo, BlockCallList, Builder, CallInfo, Datum, Extra, Flags, Func,
539 Global, InstData, Linkage, Module, Opcode, Pic, Reloc, Signature, Type, Visibility,
540 };
541 use rucc_target::{TargetInfo, Triple};
542
543 use super::{CallGraph, Node};
544
545 fn blank() -> (Interner, Module) {
547 let mut names = Interner::new();
548 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
549 let module = Module::new(names.intern("t.c"), &target);
550 (names, module)
551 }
552
553 fn calling(names: &mut Interner, module: &mut Module, name: &str, callees: &[&str]) {
555 let mut func = Func::new(names.intern(name), Signature::new());
556 let block = func.create_block();
557 let mut build = Builder::new(&mut func, block);
558 let signature = build.func().add_signature(Signature::new());
559 for callee in callees {
560 build.call(names.intern(callee), signature, &[]);
561 }
562 build.ret(&[]);
563 module.add_func(func);
564 }
565
566 fn declaring(names: &mut Interner, module: &mut Module, name: &str) {
568 module.add_func(Func::new(names.intern(name), Signature::new()));
569 }
570
571 fn node(graph: &CallGraph, names: &mut Interner, name: &str) -> Node {
573 let name = names.intern(name);
574 graph.node(name).unwrap_or_else(|| panic!("no node for {}", names.resolve(name)))
575 }
576
577 fn order(graph: &CallGraph, names: &Interner) -> Vec<Vec<String>> {
579 graph
580 .components()
581 .iter()
582 .map(|part| part.iter().map(|&it| names.resolve(graph.name(it)).to_string()).collect())
583 .collect()
584 }
585
586 #[test]
587 fn a_call_is_an_edge_and_the_callee_gets_a_node_of_its_own() {
588 let (mut names, mut module) = blank();
589 calling(&mut names, &mut module, "f", &["g"]);
590 calling(&mut names, &mut module, "g", &[]);
591 let graph = CallGraph::of(&module, Pic::Executable);
592 let (f, g) = (node(&graph, &mut names, "f"), node(&graph, &mut names, "g"));
593 assert_eq!(graph.calls(f), [g]);
594 assert_eq!(graph.calls(g), []);
595 }
596
597 #[test]
598 fn the_same_callee_twice_is_one_edge() {
599 let (mut names, mut module) = blank();
600 calling(&mut names, &mut module, "f", &["g", "h", "g"]);
601 calling(&mut names, &mut module, "g", &[]);
602 calling(&mut names, &mut module, "h", &[]);
603 let graph = CallGraph::of(&module, Pic::Executable);
604 let f = node(&graph, &mut names, "f");
605 let (g, h) = (node(&graph, &mut names, "g"), node(&graph, &mut names, "h"));
606 assert_eq!(graph.calls(f), [g, h], "the order the body calls them, each once");
607 }
608
609 #[test]
610 fn a_name_the_module_never_declared_still_gets_a_node() {
611 let (mut names, mut module) = blank();
612 calling(&mut names, &mut module, "f", &["witness"]);
613 let graph = CallGraph::of(&module, Pic::Executable);
614 let witness = node(&graph, &mut names, "witness");
615 assert_eq!(graph.calls(node(&graph, &mut names, "f")), [witness]);
616 assert_eq!(graph.func(witness), None);
617 assert_eq!(graph.trusted_body(witness), None);
618 assert!(graph.reaches_unknown(witness), "its body is somewhere this graph cannot see");
619 }
620
621 #[test]
622 fn a_declaration_has_a_function_and_no_body_and_reaches_the_unknown() {
623 let (mut names, mut module) = blank();
624 declaring(&mut names, &mut module, "printf");
625 let graph = CallGraph::of(&module, Pic::Executable);
626 let printf = node(&graph, &mut names, "printf");
627 assert!(graph.func(printf).is_some());
628 assert_eq!(graph.trusted_body(printf), None);
629 assert!(graph.reaches_unknown(printf));
630 }
631
632 #[test]
633 fn a_body_this_link_will_keep_is_one_an_analysis_may_read() {
634 let (mut names, mut module) = blank();
635 calling(&mut names, &mut module, "f", &[]);
636 let graph = CallGraph::of(&module, Pic::Executable);
637 let f = node(&graph, &mut names, "f");
638 assert!(graph.trusted_body(f).is_some());
639 assert!(!graph.reaches_unknown(f));
640 }
641
642 #[test]
643 fn a_weak_definition_is_not_a_body_this_analysis_may_read() {
644 let (mut names, mut module) = blank();
645 calling(&mut names, &mut module, "f", &[]);
646 let id = module.funcs().next().expect("the one function");
647 module[id].linkage = Linkage::Weak;
648 let graph = CallGraph::of(&module, Pic::Executable);
649 let f = node(&graph, &mut names, "f");
650 assert!(graph.func(f).is_some(), "the declaration is still there");
651 assert_eq!(graph.trusted_body(f), None, "another object may win over it");
652 assert!(graph.reaches_unknown(f));
653 }
654
655 #[test]
656 fn an_exported_definition_in_a_library_may_be_interposed_and_a_hidden_one_may_not() {
657 let (mut names, mut module) = blank();
658 calling(&mut names, &mut module, "f", &[]);
659 let id = module.funcs().next().expect("the one function");
660 let graph = CallGraph::of(&module, Pic::Library);
661 assert_eq!(graph.trusted_body(node(&graph, &mut names, "f")), None);
662 module[id].visibility = Visibility::Hidden;
663 let graph = CallGraph::of(&module, Pic::Library);
664 assert!(graph.trusted_body(node(&graph, &mut names, "f")).is_some());
665 }
666
667 #[test]
668 fn a_call_through_an_address_is_the_flag_and_not_an_edge() {
669 let (mut names, mut module) = blank();
670 let mut func = Func::new(names.intern("f"), Signature::new());
671 let block = func.create_block();
672 let mut build = Builder::new(&mut func, block);
673 let extra = Extra::Symbol(names.intern("g"));
674 let target =
675 build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
676 let signature = build.func().add_signature(Signature::new());
677 let varargs = build.func().push_abis(&[]);
678 let info = build.func().add_call(CallInfo { callee: None, signature, varargs });
679 let args = build.func().push_values(&[target]);
680 build.inst(
681 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::CallIndirect) },
682 &[],
683 );
684 build.ret(&[]);
685 module.add_func(func);
686 calling(&mut names, &mut module, "g", &[]);
687 let graph = CallGraph::of(&module, Pic::Executable);
688 let f = node(&graph, &mut names, "f");
689 assert_eq!(graph.calls(f), [], "nothing here names what is at the other end");
690 assert!(graph.reaches_unknown(f));
691 assert!(graph.address_taken(node(&graph, &mut names, "g")));
692 }
693
694 #[test]
695 fn a_function_named_in_an_image_has_had_its_address_taken() {
696 let (mut names, mut module) = blank();
697 calling(&mut names, &mut module, "handler", &[]);
698 let handler = names.intern("handler");
699 let reloc = module.add_reloc(Reloc { symbol: handler, addend: 0, size: 8 });
700 let mut table = Global::new(names.intern("table"), 8, 8);
701 table.init = Some(module.push_data(&[Datum::Addr(reloc)]));
702 module.add_global(table);
703 let graph = CallGraph::of(&module, Pic::Executable);
704 assert!(graph.address_taken(node(&graph, &mut names, "handler")));
705 }
706
707 #[test]
708 fn taking_the_address_of_a_variable_puts_nothing_in_the_graph() {
709 let (mut names, mut module) = blank();
710 let mut func = Func::new(names.intern("f"), Signature::new());
711 let block = func.create_block();
712 let mut build = Builder::new(&mut func, block);
713 let extra = Extra::Symbol(names.intern("counter"));
714 build.value(InstData { extra, ..InstData::new(Opcode::GlobalAddr) }, Type::PTR);
715 build.ret(&[]);
716 module.add_func(func);
717 module.add_global(Global::new(names.intern("counter"), 4, 4));
718 let graph = CallGraph::of(&module, Pic::Executable);
719 assert_eq!(graph.len(), 1, "the one function and nothing else");
720 assert_eq!(graph.node(names.intern("counter")), None);
721 }
722
723 #[test]
724 fn an_alias_is_an_edge_to_what_it_aliases() {
725 let (mut names, mut module) = blank();
726 calling(&mut names, &mut module, "caller", &["shorthand"]);
727 calling(&mut names, &mut module, "real", &[]);
728 module.add_alias(Alias::new(names.intern("shorthand"), names.intern("real")));
729 let graph = CallGraph::of(&module, Pic::Executable);
730 let shorthand = node(&graph, &mut names, "shorthand");
731 let real = node(&graph, &mut names, "real");
732 assert_eq!(graph.calls(node(&graph, &mut names, "caller")), [shorthand]);
733 assert_eq!(graph.calls(shorthand), [real], "a call to the alias is a call to the body");
734 }
735
736 #[test]
737 fn an_ifunc_reaches_the_unknown_and_its_resolver_has_had_its_address_taken() {
738 let (mut names, mut module) = blank();
739 calling(&mut names, &mut module, "resolve", &[]);
740 let mut alias = Alias::new(names.intern("memcpy"), names.intern("resolve"));
741 alias.kind = AliasKind::IFunc;
742 module.add_alias(alias);
743 let graph = CallGraph::of(&module, Pic::Executable);
744 let memcpy = node(&graph, &mut names, "memcpy");
745 assert_eq!(graph.calls(memcpy), [], "what it resolves to is not a name this module has");
746 assert!(graph.reaches_unknown(memcpy));
747 assert!(graph.address_taken(node(&graph, &mut names, "resolve")));
748 assert!(!graph.address_taken(memcpy));
749 }
750
751 #[test]
752 fn inline_assembly_reaches_the_unknown() {
753 let (mut names, mut module) = blank();
754 let mut func = Func::new(names.intern("f"), Signature::new());
755 let block = func.create_block();
756 let mut build = Builder::new(&mut func, block);
757 build.inline_asm(
758 AsmInfo {
759 template: names.intern("nop"),
760 constraints: names.intern(""),
761 clobbers: names.intern(""),
762 targets: BlockCallList::EMPTY,
763 },
764 &[],
765 &[],
766 Flags::NONE,
767 );
768 build.ret(&[]);
769 module.add_func(func);
770 let graph = CallGraph::of(&module, Pic::Executable);
771 assert!(graph.reaches_unknown(node(&graph, &mut names, "f")));
772 }
773
774 #[test]
775 fn a_target_intrinsic_reaches_the_unknown() {
776 let (mut names, mut module) = blank();
777 let mut func = Func::new(names.intern("f"), Signature::new());
778 let block = func.create_block();
779 let mut build = Builder::new(&mut func, block);
780 let extra = Extra::Symbol(names.intern("x86.pause"));
781 build.inst(InstData { extra, ..InstData::new(Opcode::TargetIntrinsic) }, &[]);
782 build.ret(&[]);
783 module.add_func(func);
784 let graph = CallGraph::of(&module, Pic::Executable);
785 assert!(graph.reaches_unknown(node(&graph, &mut names, "f")));
786 }
787
788 #[test]
789 fn a_chain_of_callers_comes_out_callee_before_caller() {
790 let (mut names, mut module) = blank();
791 calling(&mut names, &mut module, "top", &["middle"]);
792 calling(&mut names, &mut module, "middle", &["bottom"]);
793 calling(&mut names, &mut module, "bottom", &[]);
794 let graph = CallGraph::of(&module, Pic::Executable);
795 assert_eq!(order(&graph, &names), [["bottom"], ["middle"], ["top"]]);
796 }
797
798 #[test]
799 fn a_function_that_calls_itself_is_a_component_of_one_that_is_a_cycle() {
800 let (mut names, mut module) = blank();
801 calling(&mut names, &mut module, "spin", &["spin"]);
802 let graph = CallGraph::of(&module, Pic::Executable);
803 let spin = node(&graph, &mut names, "spin");
804 assert_eq!(graph.calls(spin), [spin]);
805 assert_eq!(order(&graph, &names), [["spin"]]);
806 }
807
808 #[test]
809 fn two_functions_that_call_each_other_are_one_component() {
810 let (mut names, mut module) = blank();
811 calling(&mut names, &mut module, "even", &["odd"]);
812 calling(&mut names, &mut module, "odd", &["even"]);
813 calling(&mut names, &mut module, "main", &["even"]);
814 let graph = CallGraph::of(&module, Pic::Executable);
815 assert_eq!(order(&graph, &names), [vec!["even", "odd"], vec!["main"]]);
816 let (even, odd) = (node(&graph, &mut names, "even"), node(&graph, &mut names, "odd"));
817 assert_eq!(graph.component_of(even), graph.component_of(odd));
818 }
819
820 #[test]
821 fn a_component_holds_its_nodes_in_the_graphs_own_order() {
822 let (mut names, mut module) = blank();
823 calling(&mut names, &mut module, "a", &["c"]);
826 calling(&mut names, &mut module, "b", &["a"]);
827 calling(&mut names, &mut module, "c", &["b"]);
828 let graph = CallGraph::of(&module, Pic::Executable);
829 assert_eq!(order(&graph, &names), [["a", "b", "c"]]);
830 let a = node(&graph, &mut names, "a");
831 assert_eq!(graph.components()[graph.component_of(a)][0], a);
832 }
833
834 #[test]
835 fn the_walk_settles_a_component_before_anything_that_calls_into_it() {
836 let (mut names, mut module) = blank();
837 calling(&mut names, &mut module, "top", &["middle"]);
838 calling(&mut names, &mut module, "middle", &["bottom"]);
839 calling(&mut names, &mut module, "bottom", &[]);
840 let graph = CallGraph::of(&module, Pic::Executable);
841 let depth = graph.solve(
844 |_| 0usize,
845 |node, answers| {
846 graph.calls(node).iter().map(|&it| answers[it.index()] + 1).max().unwrap_or(0)
847 },
848 );
849 assert_eq!(depth[node(&graph, &mut names, "bottom").index()], 0);
850 assert_eq!(depth[node(&graph, &mut names, "middle").index()], 1);
851 assert_eq!(depth[node(&graph, &mut names, "top").index()], 2);
852 }
853
854 #[test]
855 fn a_component_of_one_with_no_edge_to_itself_is_asked_once() {
856 let (mut names, mut module) = blank();
857 calling(&mut names, &mut module, "f", &["g"]);
858 calling(&mut names, &mut module, "g", &[]);
859 let graph = CallGraph::of(&module, Pic::Executable);
860 let mut asked = 0usize;
861 let answers: Vec<bool> = graph.solve(
862 |_| false,
863 |_, _| {
864 asked += 1;
865 true
866 },
867 );
868 assert_eq!(asked, 2, "one question each, with nothing to settle");
869 assert!(answers[node(&graph, &mut names, "f").index()]);
870 }
871
872 #[test]
873 fn a_cycle_is_iterated_until_nothing_moves() {
874 let (mut names, mut module) = blank();
875 calling(&mut names, &mut module, "even", &["odd"]);
876 calling(&mut names, &mut module, "odd", &["even"]);
877 let graph = CallGraph::of(&module, Pic::Executable);
878 let odd = node(&graph, &mut names, "odd");
881 let settled = graph.solve(
882 |_| true,
883 |node, answers| node != odd && graph.calls(node).iter().all(|&it| answers[it.index()]),
884 );
885 assert!(!settled[odd.index()]);
886 assert!(!settled[node(&graph, &mut names, "even").index()], "through the cycle");
887 }
888
889 #[test]
890 fn an_empty_module_is_an_empty_graph() {
891 let (_, module) = blank();
892 let graph = CallGraph::of(&module, Pic::Executable);
893 assert!(graph.is_empty());
894 assert_eq!(graph.len(), 0);
895 assert!(graph.components().is_empty());
896 let answers: Vec<usize> = graph.solve(|_| 0, |_, _| 0);
897 assert!(answers.is_empty());
898 }
899
900 #[test]
901 fn the_graph_is_the_same_graph_every_time_it_is_built() {
902 let (mut names, mut module) = blank();
903 for name in ["one", "two", "three", "four", "five"] {
904 calling(&mut names, &mut module, name, &["helper", "one"]);
905 }
906 calling(&mut names, &mut module, "helper", &[]);
907 let first = CallGraph::of(&module, Pic::Executable);
908 let spelling = |graph: &CallGraph| {
909 graph
910 .nodes()
911 .map(|it| {
912 let calls: Vec<&str> =
913 graph.calls(it).iter().map(|&to| names.resolve(graph.name(to))).collect();
914 (names.resolve(graph.name(it)).to_string(), calls.join(" "))
915 })
916 .collect::<Vec<_>>()
917 };
918 for _ in 0..8 {
919 let again = CallGraph::of(&module, Pic::Executable);
920 assert_eq!(spelling(&first), spelling(&again));
921 assert_eq!(order(&first, &names), order(&again, &names));
922 }
923 }
924
925 #[test]
926 fn a_chain_deeper_than_a_recursive_walk_could_manage_still_comes_out_in_order() {
927 let (mut names, mut module) = blank();
928 let deep = 20_000;
929 for at in 0..deep {
930 let next = format!("f{}", at + 1);
931 calling(&mut names, &mut module, &format!("f{at}"), &[next.as_str()]);
932 }
933 let graph = CallGraph::of(&module, Pic::Executable);
934 assert_eq!(graph.components().len(), deep + 1, "the tail name gets one of its own");
935 let top = node(&graph, &mut names, "f0");
936 assert_eq!(graph.component_of(top), deep, "settled last, after everything under it");
937 }
938}