rapx/analysis/core/api_dependency/
mod.rs

1/// NOTE: This analysis module is currently under development and is highly unstable.
2/// The #[allow(unused)] attribute is applied to suppress excessive lint warnings.
3/// Once the analysis stabilizes, this marker should be removed.
4
5#[allow(unused)]
6pub mod graph;
7mod mono;
8mod utils;
9#[allow(unused)]
10mod visitor;
11
12use crate::analysis::Analysis;
13pub use graph::ApiDependencyGraph;
14pub use graph::{DepEdge, DepNode};
15use rustc_hir::def_id::{DefId, LOCAL_CRATE};
16use rustc_middle::ty::TyCtxt;
17pub use utils::is_fuzzable_ty;
18
19#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Default)]
20pub struct Config {
21    pub pub_only: bool,
22    pub resolve_generic: bool,
23    pub ignore_const_generic: bool,
24}
25
26pub fn is_def_id_public(fn_def_id: impl Into<DefId>, tcx: TyCtxt<'_>) -> bool {
27    let fn_def_id: DefId = fn_def_id.into();
28    let local_id = fn_def_id.expect_local();
29    rap_trace!(
30        "vis: {:?} (path: {}) => {:?}",
31        fn_def_id,
32        tcx.def_path_str(fn_def_id),
33        tcx.effective_visibilities(()).effective_vis(local_id)
34    );
35    tcx.effective_visibilities(()).is_directly_public(local_id)
36    // || tcx.effective_visibilities(()).is_exported(local_id)
37}
38
39pub trait ApiDependencyAnalysis<'tcx> {
40    fn get_api_dependency_graph(&self) -> ApiDependencyGraph<'tcx>;
41}
42
43pub struct ApiDependencyAnalyzer<'tcx> {
44    tcx: TyCtxt<'tcx>,
45    config: Config,
46    api_graph: ApiDependencyGraph<'tcx>,
47}
48
49impl<'tcx> ApiDependencyAnalyzer<'tcx> {
50    pub fn new(tcx: TyCtxt<'tcx>, config: Config) -> ApiDependencyAnalyzer<'tcx> {
51        ApiDependencyAnalyzer {
52            tcx,
53            config,
54            api_graph: ApiDependencyGraph::new(tcx),
55        }
56    }
57}
58
59impl<'tcx> Analysis for ApiDependencyAnalyzer<'tcx> {
60    fn name(&self) -> &'static str {
61        "Default API dependency graph analysis algorithm."
62    }
63
64    fn run(&mut self) {
65        let local_crate_name = self.tcx.crate_name(LOCAL_CRATE);
66        let local_crate_type = self.tcx.crate_types()[0];
67        let config = self.config;
68        rap_debug!(
69            "Build API dependency graph on {} ({}), config = {:?}",
70            local_crate_name.as_str(),
71            local_crate_type,
72            config,
73        );
74
75        let mut api_graph = ApiDependencyGraph::new(self.tcx);
76        api_graph.build(config);
77
78        let (estimate, total) = api_graph.estimate_coverage();
79
80        let statistics = api_graph.statistics();
81        // print all statistics
82        rap_info!(
83            "API Graph contains {} API nodes, {} type nodes, {} edges",
84            statistics.api_count,
85            statistics.type_count,
86            statistics.edge_cnt
87        );
88        rap_info!(
89            "estimate coverage: {:.2} ({}/{})",
90            estimate as f64 / total as f64,
91            estimate,
92            total
93        );
94        let dot_path = format!("api_graph_{}_{}.dot", local_crate_name, local_crate_type);
95        let json_path = format!("api_graph_{}_{}.json", local_crate_name, local_crate_type);
96        rap_info!("Dump API dependency graph to {}", dot_path);
97        api_graph.dump_to_dot(dot_path, self.tcx);
98        api_graph
99            .dump_to_json(&json_path)
100            .expect("failed to dump API graph to JSON");
101        rap_info!("Dump API dependency graph to {}", json_path);
102    }
103
104    fn reset(&mut self) {
105        todo!();
106    }
107}
108
109impl<'tcx> ApiDependencyAnalysis<'tcx> for ApiDependencyAnalyzer<'tcx> {
110    fn get_api_dependency_graph(&self) -> ApiDependencyGraph<'tcx> {
111        self.api_graph.clone()
112    }
113}