1use rayon::prelude::*;
2
3use crate::block::{BasicBlock, BlockId, BlockRelation};
4use crate::context::{CompileCtxt, CompileUnit};
5
6#[derive(Debug, Clone)]
7pub struct UnitGraph {
8 unit_index: usize,
10 root: BlockId,
12}
13
14impl UnitGraph {
15 pub fn new(unit_index: usize, root: BlockId) -> Self {
16 Self { unit_index, root }
17 }
18
19 pub fn unit_index(&self) -> usize {
20 self.unit_index
21 }
22
23 pub fn root(&self) -> BlockId {
24 self.root
25 }
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub struct UnitNode {
30 pub unit_index: usize,
31 pub block_id: BlockId,
32}
33
34#[derive(Debug)]
37pub struct ProjectGraph<'tcx> {
38 pub cc: &'tcx CompileCtxt<'tcx>,
40 units: Vec<UnitGraph>,
42}
43
44impl<'tcx> ProjectGraph<'tcx> {
45 pub fn new(cc: &'tcx CompileCtxt<'tcx>) -> Self {
46 Self {
47 cc,
48 units: Vec::new(),
49 }
50 }
51
52 pub fn add_child(&mut self, graph: UnitGraph) {
53 self.units.push(graph);
54 self.units.sort_by_key(|g| g.unit_index());
55 }
56
57 pub fn add_children(&mut self, graphs: Vec<UnitGraph>) {
59 self.units.extend(graphs);
60 self.units.sort_by_key(|g| g.unit_index());
61 }
62
63 pub fn units(&self) -> &[UnitGraph] {
65 &self.units
66 }
67
68 pub fn unit_graph(&self, index: usize) -> Option<&UnitGraph> {
70 self.units.iter().find(|u| u.unit_index() == index)
71 }
72
73 pub fn top_k(&self) -> Option<usize> {
75 None
76 }
77
78 pub fn pagerank_enabled(&self) -> bool {
80 false
81 }
82
83 pub fn connect_blocks(&self) {
85 self.units.par_iter().for_each(|unit_graph| {
87 let unit = CompileUnit {
88 cc: self.cc,
89 index: unit_graph.unit_index(),
90 };
91 let root_block = unit.bb(unit_graph.root());
92 self.dfs_connect(&unit, &root_block, None);
93 });
94 }
95
96 fn dfs_connect(
98 &self,
99 unit: &CompileUnit<'tcx>,
100 block: &BasicBlock<'tcx>,
101 parent: Option<BlockId>,
102 ) {
103 let block_id = block.id();
104
105 if let Some(parent_id) = parent {
107 self.add_relation(parent_id, BlockRelation::Contains, block_id);
108 self.add_relation(block_id, BlockRelation::ContainedBy, parent_id);
109 }
110
111 match block {
113 BasicBlock::Func(func) => self.link_func(unit, block_id, func),
114 BasicBlock::Class(class) => self.link_class(unit, block_id, class),
115 BasicBlock::Impl(impl_block) => self.link_impl(unit, block_id, impl_block),
116 BasicBlock::Trait(trait_block) => self.link_trait(unit, block_id, trait_block),
117 BasicBlock::Interface(iface_block) => self.link_interface(unit, block_id, iface_block),
118 BasicBlock::Enum(enum_block) => self.link_enum(unit, block_id, enum_block),
119 BasicBlock::Call(call) => self.link_call(unit, block_id, call),
120 BasicBlock::Field(field) => self.link_field(unit, block_id, field),
121 BasicBlock::Return(ret) => self.link_return(unit, block_id, ret),
122 BasicBlock::Parameter(param) => self.link_parameter(unit, block_id, param),
123 BasicBlock::Const(const_block) => self.link_const(unit, block_id, const_block),
124 BasicBlock::Alias(alias) => self.link_alias(unit, block_id, alias),
125 _ => {}
127 }
128
129 for child_id in block.children() {
131 let child = unit.bb(child_id);
132 self.dfs_connect(unit, &child, Some(block_id));
133 }
134 }
135
136 #[inline]
138 fn add_relation(&self, from: BlockId, relation: BlockRelation, to: BlockId) {
139 self.cc.related_map.add_relation_impl(from, relation, to);
140 }
141
142 fn link_func(
144 &self,
145 unit: &CompileUnit<'tcx>,
146 block_id: BlockId,
147 func: &crate::block::BlockFunc<'tcx>,
148 ) {
149 for param_id in func.get_parameters() {
151 self.add_relation(block_id, BlockRelation::HasParameters, param_id);
152 }
153
154 if let Some(ret_id) = func.get_returns() {
156 self.add_relation(block_id, BlockRelation::HasReturn, ret_id);
157 }
158
159 if let Some(func_sym) = func.base.symbol
162 && let Some(scope_id) = func_sym.opt_scope()
163 {
164 let scope = unit.get_scope(scope_id);
165 scope.for_each_symbol(|sym| {
167 if sym.kind() == crate::symbol::SymKind::TypeParameter {
168 if let Some(bound_id) = sym.type_of()
170 && let Some(bound_sym) = unit.opt_get_symbol(bound_id)
171 && let Some(bound_block_id) = bound_sym.block_id()
172 {
173 self.add_relation(bound_block_id, BlockRelation::UsedBy, block_id);
176 self.add_relation(block_id, BlockRelation::Uses, bound_block_id);
177 }
178 }
179 });
180 }
181
182 if let Some(func_sym) = func.base.symbol
185 && let Some(nested_types) = func_sym.nested_types()
186 {
187 for type_id in nested_types {
188 let type_sym = unit.opt_get_symbol(type_id).and_then(|sym| {
190 sym.type_of()
191 .and_then(|id| unit.opt_get_symbol(id))
192 .or(Some(sym))
193 });
194 if let Some(type_sym) = type_sym
195 && let Some(type_block_id) = type_sym.block_id()
196 {
197 func.add_type_dep(type_block_id);
198 }
199 }
200 }
201
202 if let Some(func_sym) = func.base.symbol
204 && let Some(decorators) = func_sym.decorators()
205 {
206 for decorator_id in decorators {
207 if let Some(decorator_sym) = unit.opt_get_symbol(decorator_id)
208 && let Some(decorator_block_id) = decorator_sym.block_id()
209 {
210 func.add_type_dep(decorator_block_id);
211 }
212 }
213 }
214
215 for child_id in func.base.get_children() {
218 self.find_calls_recursive(unit, block_id, func, child_id);
219 }
220
221 for type_id in func.get_type_deps() {
223 self.add_relation(block_id, BlockRelation::Uses, type_id);
224 self.add_relation(type_id, BlockRelation::UsedBy, block_id);
225 }
226
227 for type_id in func.get_func_deps() {
229 self.add_relation(block_id, BlockRelation::Calls, type_id);
230 self.add_relation(type_id, BlockRelation::CalledBy, block_id);
231 }
232 }
233
234 fn find_calls_recursive(
237 &self,
238 unit: &CompileUnit<'tcx>,
239 caller_func_id: BlockId,
240 caller_func: &crate::block::BlockFunc<'tcx>,
241 block_id: BlockId,
242 ) {
243 let block = unit.bb(block_id);
244
245 if let BasicBlock::Call(call) = &block {
247 if let Some(callee_sym) = call.base.node.ident_symbol(unit) {
249 self.process_callee_symbol(unit, caller_func_id, caller_func, callee_sym);
250 }
251 }
252
253 if let Some(base) = block.base() {
258 let node = &base.node;
259 if let Some(callee_sym) = node.ident_symbol(unit) {
261 let kind = callee_sym.kind();
262 if !matches!(&block, BasicBlock::Call(_))
264 && matches!(
265 kind,
266 crate::symbol::SymKind::Function
267 | crate::symbol::SymKind::Struct
268 | crate::symbol::SymKind::Enum
269 )
270 {
271 self.process_callee_symbol(unit, caller_func_id, caller_func, callee_sym);
272 }
273 }
274 }
275
276 for child_id in block.children() {
278 self.find_calls_recursive(unit, caller_func_id, caller_func, child_id);
279 }
280 }
281
282 fn process_callee_symbol(
284 &self,
285 _unit: &CompileUnit<'tcx>,
286 caller_func_id: BlockId,
287 caller_func: &crate::block::BlockFunc<'tcx>,
288 callee_sym: &crate::symbol::Symbol,
289 ) {
290 let callee_kind = callee_sym.kind();
291 let callee_block_id_opt = callee_sym.block_id();
292
293 match callee_kind {
294 crate::symbol::SymKind::Function => {
295 if let Some(callee_block_id) = callee_block_id_opt {
297 caller_func.add_func_dep(callee_block_id);
298 self.add_relation(caller_func_id, BlockRelation::Calls, callee_block_id);
300 self.add_relation(callee_block_id, BlockRelation::CalledBy, caller_func_id);
301 }
302 }
303 crate::symbol::SymKind::Method => {
304 if let Some(type_sym_id) = callee_sym.type_of()
307 && let Some(type_sym) = self.cc.opt_get_symbol(type_sym_id)
308 && let Some(type_block_id) = type_sym.block_id()
309 {
310 caller_func.add_type_dep(type_block_id);
311 }
312 if let Some(callee_block_id) = callee_sym.block_id() {
314 self.add_relation(caller_func_id, BlockRelation::Calls, callee_block_id);
315 self.add_relation(callee_block_id, BlockRelation::CalledBy, caller_func_id);
316 }
317 }
318 _ => {
319 if let Some(callee_block_id) = callee_sym.block_id()
322 && (callee_kind == crate::symbol::SymKind::Struct
323 || callee_kind == crate::symbol::SymKind::Enum)
324 {
325 caller_func.add_type_dep(callee_block_id);
326 self.add_relation(caller_func_id, BlockRelation::Uses, callee_block_id);
328 self.add_relation(callee_block_id, BlockRelation::UsedBy, caller_func_id);
329 }
330 }
331 }
332 }
333
334 fn link_class(
336 &self,
337 unit: &CompileUnit<'tcx>,
338 block_id: BlockId,
339 class: &crate::block::BlockClass<'tcx>,
340 ) {
341 for field_id in class.get_fields() {
343 self.add_relation(block_id, BlockRelation::HasField, field_id);
344 self.add_relation(field_id, BlockRelation::FieldOf, block_id);
345 }
346
347 for method_id in class.get_methods() {
349 self.add_relation(block_id, BlockRelation::HasMethod, method_id);
350 self.add_relation(method_id, BlockRelation::MethodOf, block_id);
351 }
352
353 if let Some(class_sym) = class.base.symbol {
354 if let Some(extends_id) = class_sym.type_of()
356 && let Some(extends_sym) = unit.opt_get_symbol(extends_id)
357 && let Some(extends_block_id) = extends_sym.block_id()
358 {
359 self.add_relation(block_id, BlockRelation::Extends, extends_block_id);
361 self.add_relation(extends_block_id, BlockRelation::ExtendedBy, block_id);
362
363 let extends_name = unit.resolve_name(extends_sym.name);
365 class.set_extends(extends_name, Some(extends_block_id));
366 }
367
368 if let Some(nested) = class_sym.nested_types() {
372 for type_id in nested {
373 if let Some(type_sym) = unit.opt_get_symbol(type_id)
374 && let Some(type_block_id) = type_sym.block_id()
375 {
376 class.base.add_type_dep(type_block_id);
378
379 let is_trait = type_sym.kind() == crate::symbol::SymKind::Trait;
382 let is_interface = type_sym.kind() == crate::symbol::SymKind::Interface;
383
384 if is_trait {
385 self.add_relation(block_id, BlockRelation::Uses, type_block_id);
388 self.add_relation(type_block_id, BlockRelation::UsedBy, block_id);
389 } else if is_interface {
390 self.add_relation(block_id, BlockRelation::Implements, type_block_id);
392 self.add_relation(
393 type_block_id,
394 BlockRelation::ImplementedBy,
395 block_id,
396 );
397 }
398 }
399 }
400 }
401
402 if let Some(decorators) = class_sym.decorators() {
404 for decorator_id in decorators {
405 if let Some(decorator_sym) = unit.opt_get_symbol(decorator_id)
406 && let Some(decorator_block_id) = decorator_sym.block_id()
407 {
408 class.base.add_type_dep(decorator_block_id);
410 self.add_relation(block_id, BlockRelation::Uses, decorator_block_id);
411 self.add_relation(decorator_block_id, BlockRelation::UsedBy, block_id);
412 }
413 }
414 }
415 }
416 }
419
420 fn link_impl(
422 &self,
423 unit: &CompileUnit<'tcx>,
424 block_id: BlockId,
425 impl_block: &crate::block::BlockImpl<'tcx>,
426 ) {
427 for method_id in impl_block.get_methods() {
429 self.add_relation(block_id, BlockRelation::HasMethod, method_id);
430 self.add_relation(method_id, BlockRelation::MethodOf, block_id);
431 }
432
433 let target_id = impl_block
435 .get_target()
436 .or_else(|| impl_block.target_sym.and_then(|sym| sym.block_id()));
437 if let Some(target_id) = target_id {
438 impl_block.set_target(target_id);
439 self.add_relation(block_id, BlockRelation::ImplFor, target_id);
440 self.add_relation(target_id, BlockRelation::HasImpl, block_id);
441
442 if let Some(target_sym) = impl_block.target_sym
447 && let Some(nested_types) = target_sym.nested_types()
448 {
449 let target_block = unit.bb(target_id);
450 if let Some(base) = target_block.base() {
451 for type_id in nested_types {
452 let type_sym = unit.opt_get_symbol(type_id).and_then(|sym| {
454 sym.type_of()
455 .and_then(|id| unit.opt_get_symbol(id))
456 .or(Some(sym))
457 });
458 if let Some(type_sym) = type_sym
459 && let Some(type_block_id) = type_sym.block_id()
460 {
461 base.type_deps.write().insert(type_block_id);
462 }
463 }
464 }
465 }
466 }
467
468 let trait_id = impl_block
470 .get_trait_ref()
471 .or_else(|| impl_block.trait_sym.and_then(|sym| sym.block_id()));
472 if let Some(trait_id) = trait_id {
473 impl_block.set_trait_ref(trait_id);
474 self.add_relation(block_id, BlockRelation::Implements, trait_id);
475 self.add_relation(trait_id, BlockRelation::ImplementedBy, block_id);
476 }
477 }
478
479 fn link_trait(
481 &self,
482 unit: &CompileUnit<'tcx>,
483 block_id: BlockId,
484 trait_block: &crate::block::BlockTrait<'tcx>,
485 ) {
486 for method_id in trait_block.get_methods() {
488 self.add_relation(block_id, BlockRelation::HasMethod, method_id);
489 self.add_relation(method_id, BlockRelation::MethodOf, block_id);
490 }
491
492 if let Some(trait_sym) = trait_block.base.symbol
495 && let Some(scope_id) = trait_sym.opt_scope()
496 {
497 let scope = unit.get_scope(scope_id);
498 scope.for_each_symbol(|sym| {
500 if sym.kind() == crate::symbol::SymKind::TypeParameter {
501 if let Some(bound_id) = sym.type_of()
503 && let Some(bound_sym) = unit.opt_get_symbol(bound_id)
504 && let Some(bound_block_id) = bound_sym.block_id()
505 {
506 self.add_relation(bound_block_id, BlockRelation::UsedBy, block_id);
509 self.add_relation(block_id, BlockRelation::Uses, bound_block_id);
510 }
511 }
512 });
513 }
514 }
515
516 fn link_interface(
518 &self,
519 unit: &CompileUnit<'tcx>,
520 block_id: BlockId,
521 iface_block: &crate::block::BlockInterface<'tcx>,
522 ) {
523 for method_id in iface_block.get_methods() {
525 self.add_relation(block_id, BlockRelation::HasMethod, method_id);
526 self.add_relation(method_id, BlockRelation::MethodOf, block_id);
527 }
528
529 for field_id in iface_block.get_fields() {
531 self.add_relation(block_id, BlockRelation::HasField, field_id);
532 self.add_relation(field_id, BlockRelation::FieldOf, block_id);
533 }
534
535 if let Some(iface_sym) = iface_block.base.symbol
537 && let Some(nested) = iface_sym.nested_types()
538 {
539 for base_type_id in nested {
540 if let Some(base_sym) = unit.opt_get_symbol(base_type_id)
541 && let Some(base_block_id) = base_sym.block_id()
542 {
543 self.add_relation(block_id, BlockRelation::Extends, base_block_id);
545 self.add_relation(base_block_id, BlockRelation::ExtendedBy, block_id);
546
547 let base_name = unit.resolve_name(base_sym.name);
549 iface_block.add_extends(base_name, Some(base_block_id));
550 }
551 }
552 }
553
554 if let Some(iface_sym) = iface_block.base.symbol
556 && let Some(scope_id) = iface_sym.opt_scope()
557 {
558 let scope = unit.get_scope(scope_id);
559 scope.for_each_symbol(|sym| {
561 if sym.kind() == crate::symbol::SymKind::TypeParameter {
562 if let Some(bound_id) = sym.type_of()
564 && let Some(bound_sym) = unit.opt_get_symbol(bound_id)
565 && let Some(bound_block_id) = bound_sym.block_id()
566 {
567 self.add_relation(bound_block_id, BlockRelation::UsedBy, block_id);
570 self.add_relation(block_id, BlockRelation::Uses, bound_block_id);
571 }
572 }
573 });
574 }
575 }
576
577 fn link_enum(
579 &self,
580 _unit: &CompileUnit<'tcx>,
581 block_id: BlockId,
582 enum_block: &crate::block::BlockEnum<'tcx>,
583 ) {
584 for variant_id in enum_block.get_variants() {
586 self.add_relation(block_id, BlockRelation::HasField, variant_id);
587 self.add_relation(variant_id, BlockRelation::FieldOf, block_id);
588 }
589 }
591
592 fn link_call(
594 &self,
595 _unit: &CompileUnit<'tcx>,
596 block_id: BlockId,
597 call: &crate::block::BlockCall<'tcx>,
598 ) {
599 if let Some(callee_id) = call.get_callee() {
602 self.add_relation(block_id, BlockRelation::Calls, callee_id);
603 self.add_relation(callee_id, BlockRelation::CalledBy, block_id);
604 }
605 }
606
607 fn link_return(
610 &self,
611 unit: &CompileUnit<'tcx>,
612 block_id: BlockId,
613 ret: &crate::block::BlockReturn<'tcx>,
614 ) {
615 if let Some(type_id) = ret.get_type_ref() {
617 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
618 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
619 return;
620 }
621
622 let type_id = self.resolve_type_ref(unit, &ret.base);
624
625 if let Some(type_id) = type_id {
626 ret.set_type_ref(type_id);
628 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
629 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
630 }
631 }
632
633 fn link_parameter(
636 &self,
637 unit: &CompileUnit<'tcx>,
638 block_id: BlockId,
639 param: &crate::block::BlockParameter<'tcx>,
640 ) {
641 if let Some(type_id) = param.get_type_ref() {
643 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
644 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
645 return;
646 }
647
648 let type_id = self.resolve_type_ref(unit, ¶m.base);
650
651 if let Some(type_id) = type_id {
652 param.set_type_ref(type_id);
654 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
655 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
656 }
657 }
658
659 fn link_field(
662 &self,
663 unit: &CompileUnit<'tcx>,
664 block_id: BlockId,
665 field: &crate::block::BlockField<'tcx>,
666 ) {
667 if let Some(type_id) = field.get_type_ref() {
670 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
671 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
672 } else {
673 let type_id = self.resolve_type_ref(unit, &field.base);
675
676 if let Some(type_id) = type_id {
677 field.set_type_ref(type_id);
679 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
680 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
681 }
682 }
683
684 for child_id in field.base.get_children() {
686 self.add_relation(block_id, BlockRelation::HasField, child_id);
687 self.add_relation(child_id, BlockRelation::FieldOf, block_id);
688 }
689 }
690
691 fn link_const(
694 &self,
695 unit: &CompileUnit<'tcx>,
696 block_id: BlockId,
697 const_block: &crate::block::BlockConst<'tcx>,
698 ) {
699 if let Some(type_id) = const_block.get_type_ref() {
701 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
702 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
703 return;
704 }
705
706 let type_id = self.resolve_type_ref(unit, &const_block.base);
708
709 if let Some(type_id) = type_id {
710 const_block.set_type_ref(type_id);
712 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
713 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
714 }
715 }
716
717 fn link_alias(
720 &self,
721 unit: &CompileUnit<'tcx>,
722 block_id: BlockId,
723 alias: &crate::block::BlockAlias<'tcx>,
724 ) {
725 let type_id = self.resolve_type_ref(unit, &alias.base);
727
728 if let Some(type_id) = type_id {
729 self.add_relation(block_id, BlockRelation::TypeOf, type_id);
730 self.add_relation(type_id, BlockRelation::TypeFor, block_id);
731 }
732 }
733
734 fn resolve_type_ref(
737 &self,
738 _unit: &CompileUnit<'tcx>,
739 base: &crate::block::BlockBase<'tcx>,
740 ) -> Option<BlockId> {
741 if let Some(sym) = base.symbol() {
743 if let Some(type_of_id) = sym.type_of()
744 && let Some(type_sym) = self.cc.opt_get_symbol(type_of_id)
745 {
746 return type_sym.block_id();
747 }
748 if crate::symbol::SYM_KIND_TYPES.contains(sym.kind()) {
751 return sym.block_id();
752 }
753 }
754 None
755 }
756}