rapx/check/opt/data_collection/suboptimal/
slice_contains.rs1use annotate_snippets::Level;
2
3use crate::{
4 analysis::dataflow::Graph, check::opt::OptCheck, check::opt::loop_visitors::MethodCallFinder,
5};
6use rustc_hir::intravisit;
7use rustc_middle::ty::TyCtxt;
8use rustc_span::Span;
9
10use crate::check::opt::report::OptReport;
11
12crate::def_paths! {
13 slice_contains: "slice::contains",
14}
15
16pub struct SliceContainsCheck {
17 record: Vec<Span>,
18}
19
20impl OptCheck for SliceContainsCheck {
21 fn new() -> Self {
22 Self { record: Vec::new() }
23 }
24
25 fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
26 DEFPATHS.get_or_init(|| DefPaths::new(tcx));
27 let def_id = graph.def_id;
28 let body = tcx.hir_body_owned_by(def_id.as_local().unwrap());
29 let typeck_results = tcx.typeck(def_id.as_local().unwrap());
30 let target_def_id = DEFPATHS.get().unwrap().slice_contains.last_def_id();
31 let mut finder = MethodCallFinder::new(typeck_results, target_def_id);
32 intravisit::walk_body(&mut finder, body);
33 self.record = finder.into_record();
34 }
35
36 fn report(&self, graph: &Graph) {
37 for contains_span in self.record.iter() {
38 report_slice_contains_bug(graph, *contains_span);
39 }
40 }
41
42 fn cnt(&self) -> usize {
43 self.record.len()
44 }
45}
46
47fn report_slice_contains_bug(graph: &Graph, contains_span: Span) {
48 OptReport::from_graph(graph)
49 .title("Improper data collection detected")
50 .annotate(Level::Error, contains_span, "Slice contains happens here.")
51 .footer("Use Set instead of Slice.")
52 .emit();
53}