Skip to main content

rapx/analysis/api_dependency/
mod.rs

1mod fuzzable;
2/// NOTE: This analysis module is currently under development and is highly unstable.
3/// The #[allow(unused)] attribute is applied to suppress excessive lint warnings.
4/// Once the analysis stabilizes, this marker should be removed.
5
6#[allow(unused)]
7pub mod graph;
8mod mono;
9mod utils;
10#[allow(unused)]
11mod visit;
12
13use crate::analysis::Analysis;
14pub use graph::ApiDependencyGraph;
15pub use graph::{DepEdge, DepNode};
16use rustc_hir::def_id::LOCAL_CRATE;
17use rustc_middle::ty::TyCtxt;
18use serde::Serialize;
19use std::path::PathBuf;
20pub use utils::{is_def_id_public, is_fuzzable_ty};
21pub use visit::Config as VisitConfig;
22
23#[derive(Debug, Clone, Serialize)]
24pub struct StatsWithCoverage {
25    pub num_apis: usize,
26    pub num_generic_apis: usize,
27    pub num_covered_apis: usize,
28    pub num_covered_generic_apis: usize,
29}
30
31#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
32pub struct Config {
33    pub resolve_generic: bool,
34    pub visit_config: visit::Config,
35    pub max_generic_search_iteration: usize,
36    pub dump: Option<PathBuf>,
37}
38
39impl Default for Config {
40    fn default() -> Self {
41        Config {
42            resolve_generic: true,
43            visit_config: VisitConfig::default(),
44            max_generic_search_iteration: 10,
45            dump: None,
46        }
47    }
48}
49
50pub struct ApiDependencyAnalyzer<'tcx> {
51    tcx: TyCtxt<'tcx>,
52    config: Config,
53    api_graph: ApiDependencyGraph<'tcx>,
54}
55
56impl<'tcx> ApiDependencyAnalyzer<'tcx> {
57    pub fn new(tcx: TyCtxt<'tcx>, config: Config) -> ApiDependencyAnalyzer<'tcx> {
58        ApiDependencyAnalyzer {
59            tcx,
60            config,
61            api_graph: ApiDependencyGraph::new(tcx),
62        }
63    }
64}
65
66impl<'tcx> Analysis for ApiDependencyAnalyzer<'tcx> {
67    fn run(&mut self) {
68        let local_crate_name = self.tcx.crate_name(LOCAL_CRATE);
69        let local_crate_type = self.tcx.crate_types()[0];
70        rap_info!(
71            "Build API dependency graph on {} ({}), config = {:?}",
72            local_crate_name.as_str(),
73            local_crate_type,
74            self.config,
75        );
76
77        let api_graph = &mut self.api_graph;
78        api_graph.build(&self.config);
79
80        let stats = api_graph.statistics();
81        stats.info();
82        let mut num_covered_apis = 0;
83        let mut num_covered_generic_apis = 0;
84        let mut num_total = 0;
85
86        api_graph.traverse_covered_api_with(
87            &mut |did| {
88                num_covered_apis += 1;
89                if utils::fn_requires_monomorphization(did, self.tcx) {
90                    num_covered_generic_apis += 1;
91                }
92            },
93            &mut |_| {
94                num_total += 1;
95            },
96        );
97
98        rap_info!("uncovered APIs: {:?}", api_graph.uncovered_api());
99
100        rap_info!(
101            "Cov API/Cov GAPI/#API/#GAPI: {}({:.2})/{}({:.2})/{}/{}",
102            num_covered_apis,
103            num_covered_apis as f64 / stats.num_api as f64,
104            num_covered_generic_apis,
105            num_covered_generic_apis as f64 / stats.num_generic_api as f64,
106            stats.num_api,
107            stats.num_generic_api
108        );
109
110        let stats_with_coverage = StatsWithCoverage {
111            num_apis: stats.num_api,
112            num_generic_apis: stats.num_generic_api,
113            num_covered_apis,
114            num_covered_generic_apis,
115        };
116
117        // dump adg stats
118        let stats_file = std::fs::File::create("adg_stats.json").unwrap();
119        serde_json::to_writer(stats_file, &stats_with_coverage)
120            .expect("failed to dump stats to JSON");
121
122        // dump API graph, determine the format base on extension name
123        if let Some(dump_path) = &self.config.dump {
124            self.api_graph
125                .dump_to_file(dump_path)
126                .inspect_err(|err| {
127                    rap_error!("{:?}", err);
128                })
129                .expect("failed to dump API graph");
130        }
131    }
132
133}
134impl<'tcx> ApiDependencyAnalyzer<'tcx> {
135    pub fn get_api_dependency_graph(&self) -> ApiDependencyGraph<'tcx> {
136        self.api_graph.clone()
137    }
138}