rapx/analysis/core/api_dependency/
visitor.rs

1use super::graph::ApiDependencyGraph;
2use super::graph::{DepEdge, DepNode};
3use super::is_def_id_public;
4use super::Config;
5use crate::analysis::core::api_dependency::mono;
6use crate::{rap_debug, rap_trace};
7use rustc_hir::{
8    def_id::{DefId, LocalDefId},
9    intravisit::{FnKind, Visitor},
10    BodyId, BodyOwnerKind, FnDecl,
11};
12use rustc_middle::ty::{self, FnSig, ParamEnv, Ty, TyCtxt, TyKind};
13use rustc_span::Span;
14use std::io::Write;
15
16pub struct FnVisitor<'tcx, 'a> {
17    tcx: TyCtxt<'tcx>,
18    apis: Vec<DefId>,
19    config: Config,
20    graph: &'a mut ApiDependencyGraph<'tcx>,
21}
22
23impl<'tcx, 'a> FnVisitor<'tcx, 'a> {
24    pub fn new(
25        graph: &'a mut ApiDependencyGraph<'tcx>,
26        config: Config,
27        tcx: TyCtxt<'tcx>,
28    ) -> FnVisitor<'tcx, 'a> {
29        let fn_cnt = 0;
30        let funcs = Vec::new();
31        FnVisitor {
32            tcx,
33            graph,
34            apis: funcs,
35            config,
36        }
37    }
38
39    pub fn count_api(&self) -> usize {
40        self.apis.len()
41    }
42
43    pub fn apis(self) -> Vec<DefId> {
44        self.apis
45    }
46
47    pub fn write_funcs<T: Write>(&self, f: &mut T) {
48        for id in &self.apis {
49            write!(f, "{}\n", self.tcx.def_path_str(id)).expect("fail when write funcs");
50        }
51    }
52}
53
54pub fn has_const_generics(generics: &ty::Generics, tcx: TyCtxt<'_>) -> bool {
55    if generics
56        .own_params
57        .iter()
58        .any(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
59    {
60        return true;
61    }
62
63    if let Some(parent_def_id) = generics.parent {
64        let parent = tcx.generics_of(parent_def_id);
65        has_const_generics(parent, tcx)
66    } else {
67        false
68    }
69}
70
71impl<'tcx, 'a> Visitor<'tcx> for FnVisitor<'tcx, 'a> {
72    fn visit_fn<'v>(
73        &mut self,
74        _fk: FnKind<'v>,
75        _fd: &'v FnDecl<'v>,
76        _b: BodyId,
77        _span: Span,
78        id: LocalDefId,
79    ) -> Self::Result {
80        let fn_did = id.to_def_id();
81        let generics = self.tcx.generics_of(fn_did);
82
83        let is_generic = generics.requires_monomorphization(self.tcx);
84        if self.config.pub_only && !is_def_id_public(fn_did, self.tcx) {
85            return;
86        }
87
88        // if config.resolve_generic is false,
89        // skip all generic functions
90        if !self.config.resolve_generic && is_generic {
91            return;
92        }
93
94        // if config.ignore_const_generic is true,
95        // skip functions with const generics
96        if self.config.ignore_const_generic && has_const_generics(generics, self.tcx) {
97            return;
98        }
99
100        if !is_generic {
101            let args = ty::GenericArgs::identity_for_item(self.tcx, fn_did);
102            self.graph.add_api(fn_did, &args);
103        }
104
105        self.apis.push(fn_did);
106    }
107}