Skip to main content

rapx/check/opt/data_collection/initialization/
local_set.rs

1use annotate_snippets::Level;
2
3use crate::{
4    analysis::dataflow::*,
5    check::opt::OptCheck,
6};
7use rustc_middle::{mir::Local, ty::TyCtxt};
8use rustc_span::Span;
9
10use crate::check::opt::report::OptReport;
11use crate::check::opt::check_utils::node_matches_any_call;
12
13crate::def_paths! {
14    hashset_new: "std::collections::HashSet::new",
15    hashset_with_capacity: "std::collections::HashSet::with_capacity",
16    hashmap_new: "std::collections::HashMap::new",
17    hashmap_with_capacity: "std::collections::HashMap::with_capacity",
18    btreeset_new: "std::collections::BTreeSet::new",
19    btreemap_new: "std::collections::BTreeMap::new",
20}
21
22pub struct LocalSetCheck {
23    record: Vec<Span>,
24}
25
26impl OptCheck for LocalSetCheck {
27    fn new() -> Self {
28        Self { record: Vec::new() }
29    }
30
31    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
32        let def_paths = &DEFPATHS.get_or_init(|| DefPaths::new(tcx));
33        for (node_idx, node) in graph.nodes.iter_enumerated() {
34            if node_matches_any_call(node, |id| {
35                id == def_paths.hashset_new.last_def_id()
36                    || id == def_paths.hashmap_new.last_def_id()
37                    || id == def_paths.btreemap_new.last_def_id()
38                    || id == def_paths.btreeset_new.last_def_id()
39                    || id == def_paths.hashmap_with_capacity.last_def_id()
40                    || id == def_paths.hashset_with_capacity.last_def_id()
41            }) && !graph.is_connected(Local::from_usize(0), node_idx) {
42                self.record.push(node.span);
43            }
44        }
45    }
46
47    fn report(&self, graph: &Graph) {
48        for span in self.record.iter() {
49            report_local_set(graph, *span);
50        }
51    }
52
53    fn cnt(&self) -> usize {
54        self.record.len()
55    }
56}
57
58fn report_local_set(graph: &Graph, span: Span) {
59    OptReport::from_graph(graph)
60        .file_name(span)
61        .title("Unnecessary data collection initialization detected")
62        .annotate(Level::Error, span, "Initialization happens here")
63        .footer("Move it into parameter list and use hash table to save allocation.")
64        .emit();
65}