rapx/analysis/core/api_dep/
visitor.rs1use std::io::Write;
2
3use super::extract::extract_constraints;
4use super::graph::ApiDepGraph;
5use super::graph::{DepEdge, DepNode};
6use crate::rap_debug;
7use rustc_hir::{
8 def_id::{DefId, LocalDefId},
9 intravisit::{FnKind, Visitor},
10 BodyId, FnDecl,
11};
12
13use rustc_middle::ty::{self, TyCtxt};
14use rustc_span::Span;
15
16pub struct FnVisitor<'tcx, 'a> {
17 fn_cnt: usize,
18 tcx: TyCtxt<'tcx>,
19 funcs: Vec<DefId>,
20 current_fn_did: Option<DefId>,
21 graph: &'a mut ApiDepGraph<'tcx>,
22}
23
24impl<'tcx, 'a> FnVisitor<'tcx, 'a> {
25 pub fn new(tcx: TyCtxt<'tcx>, graph: &'a mut ApiDepGraph<'tcx>) -> FnVisitor<'tcx, 'a> {
26 let fn_cnt = 0;
27 let funcs = Vec::new();
28 FnVisitor {
29 fn_cnt,
30 tcx,
31 graph,
32 funcs,
33 current_fn_did: None,
34 }
35 }
36 pub fn fn_cnt(&self) -> usize {
37 self.fn_cnt
38 }
39 pub fn write_funcs<T: Write>(&self, f: &mut T) {
40 for id in &self.funcs {
41 write!(f, "{}\n", self.tcx.def_path_str(id)).expect("fail when write funcs");
42 }
43 }
44}
45
46fn get_bound_var_attr(var: ty::BoundVariableKind) -> (String, bool) {
47 let name: String;
48 let is_lifetime;
49 match var {
50 ty::BoundVariableKind::Ty(bound_ty_kind) => {
51 is_lifetime = false;
52 name = match bound_ty_kind {
53 ty::BoundTyKind::Param(_, sym) => sym.to_string(),
54 _ => "anon".to_string(),
55 }
56 }
57 ty::BoundVariableKind::Region(bound_region_kind) => {
58 is_lifetime = true;
59 name = match bound_region_kind {
60 ty::BoundRegionKind::Named(_, name) => name.to_string(),
61 _ => "anon".to_string(),
62 }
63 }
64 ty::BoundVariableKind::Const => {
65 is_lifetime = false;
66 name = "anon const".to_string();
67 }
68 }
69 (name, is_lifetime)
70}
71
72impl<'tcx, 'a> Visitor<'tcx> for FnVisitor<'tcx, 'a> {
73 fn visit_fn<'v>(
74 &mut self,
75 fk: FnKind<'v>,
76 fd: &'v FnDecl<'v>,
77 b: BodyId,
78 span: Span,
79 id: LocalDefId,
80 ) -> Self::Result {
81 let fn_def_id = id.to_def_id();
82 self.fn_cnt += 1;
83 self.funcs.push(fn_def_id);
84 let api_node = self.graph.get_node(DepNode::api(id));
85
86 let early_fn_sig = self.tcx.fn_sig(fn_def_id);
87 let binder_fn_sig = early_fn_sig.instantiate_identity();
88 let fn_sig = self
89 .tcx
90 .liberate_late_bound_regions(fn_def_id, binder_fn_sig);
91 rap_debug!("visit {}", fn_sig);
92
93 let generics = self.tcx.generics_of(fn_def_id);
96 let early_generic_count = generics.count();
97 rap_debug!("early bound generic count = {}", early_generic_count);
98 for i in 0..early_generic_count {
99 let generic_param_def = generics.param_at(i, self.tcx);
100 rap_debug!("early bound generic#{i}: {:?}", generic_param_def);
101 let node_index = self.graph.get_node(DepNode::generic_param_def(
102 fn_def_id,
103 i,
104 generic_param_def.name,
105 !generic_param_def.kind.is_ty_or_const(),
106 ));
107 self.graph
108 .add_edge_once(api_node, node_index, DepEdge::fn2generic());
109 }
110
111 rap_debug!(
113 "late bound generic count = {}",
114 binder_fn_sig.bound_vars().len()
115 );
116 for (i, var) in binder_fn_sig.bound_vars().iter().enumerate() {
117 rap_debug!("bound var#{i}: {var:?}");
118 let (name, is_lifetime) = get_bound_var_attr(var);
119 let node_index = self.graph.get_node(DepNode::generic_param_def(
120 fn_def_id,
121 early_generic_count + i,
122 name,
123 is_lifetime,
124 ));
125 self.graph
126 .add_edge_once(api_node, node_index, DepEdge::fn2generic());
127 }
128
129 extract_constraints(fn_def_id, self.tcx);
130
131 for (no, input_ty) in fn_sig.inputs().iter().enumerate() {
133 let input_node = self.graph.get_node(DepNode::ty(*input_ty));
135 self.graph.add_edge(input_node, api_node, DepEdge::arg(no));
136 }
137
138 let output_ty = fn_sig.output();
139 let output_node = self.graph.get_node(DepNode::ty(output_ty));
140 self.graph.add_edge(api_node, output_node, DepEdge::ret());
141 rap_debug!("exit visit_fn");
142 }
143}