rapx/check/opt/data_collection/suboptimal/
participant.rs1use annotate_snippets::Level;
2
3use crate::{
4 analysis::dataflow::*,
5 check::opt::OptCheck,
6};
7use rustc_middle::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 ParticipantCheck {
23 record: Vec<Span>, }
25
26impl OptCheck for ParticipantCheck {
27 fn new() -> Self {
28 Self { record: vec![] }
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 in graph.nodes.iter() {
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 }) {
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_participant(graph, *span);
50 }
51 }
52
53 fn cnt(&self) -> usize {
54 self.record.len()
55 }
56}
57
58fn report_participant(graph: &Graph, span: Span) {
59 OptReport::from_graph(graph)
60 .file_name(span)
61 .title("Suboptimal data collection detected")
62 .annotate(Level::Error, span, "Data collection created here")
63 .footer("Use faster data collection or hash operators instead. Static container is also a choice")
64 .emit();
65}