rapx/analysis/api_dependency/
mod.rs1mod fuzzable;
2#[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 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 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}