rapx/analysis/core/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 trait ApiDependencyAnalysis<'tcx> {
51 fn get_api_dependency_graph(&self) -> ApiDependencyGraph<'tcx>;
52}
53
54pub struct ApiDependencyAnalyzer<'tcx> {
55 tcx: TyCtxt<'tcx>,
56 config: Config,
57 api_graph: ApiDependencyGraph<'tcx>,
58}
59
60impl<'tcx> ApiDependencyAnalyzer<'tcx> {
61 pub fn new(tcx: TyCtxt<'tcx>, config: Config) -> ApiDependencyAnalyzer<'tcx> {
62 ApiDependencyAnalyzer {
63 tcx,
64 config,
65 api_graph: ApiDependencyGraph::new(tcx),
66 }
67 }
68}
69
70impl<'tcx> Analysis for ApiDependencyAnalyzer<'tcx> {
71 fn name(&self) -> &'static str {
72 "Default API dependency graph analysis algorithm."
73 }
74
75 fn run(&mut self) {
76 let local_crate_name = self.tcx.crate_name(LOCAL_CRATE);
77 let local_crate_type = self.tcx.crate_types()[0];
78 rap_info!(
79 "Build API dependency graph on {} ({}), config = {:?}",
80 local_crate_name.as_str(),
81 local_crate_type,
82 self.config,
83 );
84
85 let api_graph = &mut self.api_graph;
86 api_graph.build(&self.config);
87
88 let stats = api_graph.statistics();
89 stats.info();
90 let mut num_covered_apis = 0;
91 let mut num_covered_generic_apis = 0;
92 let mut num_total = 0;
93
94 api_graph.traverse_covered_api_with(
95 &mut |did| {
96 num_covered_apis += 1;
97 if utils::fn_requires_monomorphization(did, self.tcx) {
98 num_covered_generic_apis += 1;
99 }
100 },
101 &mut |_| {
102 num_total += 1;
103 },
104 );
105
106 rap_info!("uncovered APIs: {:?}", api_graph.uncovered_api());
107
108 rap_info!(
109 "Cov API/Cov GAPI/#API/#GAPI: {}({:.2})/{}({:.2})/{}/{}",
110 num_covered_apis,
111 num_covered_apis as f64 / stats.num_api as f64,
112 num_covered_generic_apis,
113 num_covered_generic_apis as f64 / stats.num_generic_api as f64,
114 stats.num_api,
115 stats.num_generic_api
116 );
117
118 let stats_with_coverage = StatsWithCoverage {
119 num_apis: stats.num_api,
120 num_generic_apis: stats.num_generic_api,
121 num_covered_apis,
122 num_covered_generic_apis,
123 };
124
125 let stats_file = std::fs::File::create("adg_stats.json").unwrap();
127 serde_json::to_writer(stats_file, &stats_with_coverage)
128 .expect("failed to dump stats to JSON");
129
130 if let Some(dump_path) = &self.config.dump {
132 self.api_graph
133 .dump_to_file(dump_path)
134 .inspect_err(|err| {
135 rap_error!("{:?}", err);
136 })
137 .expect("failed to dump API graph");
138 }
139 }
140
141 fn reset(&mut self) {
142 todo!();
143 }
144}
145
146impl<'tcx> ApiDependencyAnalysis<'tcx> for ApiDependencyAnalyzer<'tcx> {
147 fn get_api_dependency_graph(&self) -> ApiDependencyGraph<'tcx> {
148 self.api_graph.clone()
149 }
150}