Skip to main content

rapx/check/opt/data_collection/suboptimal/
vec_remove.rs

1use annotate_snippets::Level;
2
3
4use crate::{
5    analysis::dataflow::*,
6    check::opt::OptCheck,
7};
8use rustc_middle::ty::TyCtxt;
9use rustc_span::Span;
10
11use crate::check::opt::report::OptReport;
12use crate::check::opt::check_utils::node_matches_call;
13
14crate::def_paths! {
15    vec_remove: "std::vec::Vec::remove",
16    vec_insert: "std::vec::Vec::insert",
17}
18
19
20pub struct VecRemoveCheck {
21    record: Vec<Span>,
22}
23
24fn is_0_usize(node: &GraphNode) -> bool {
25    for op in node.ops.iter() {
26        if let NodeOp::Const(desc, _) = op {
27            if desc.eq("0_usize") {
28                return true;
29            }
30        }
31    }
32    false
33}
34
35impl OptCheck for VecRemoveCheck {
36    fn new() -> Self {
37        Self { record: vec![] }
38    }
39
40    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
41        let def_paths = &DEFPATHS.get_or_init(|| DefPaths::new(tcx));
42        for node in graph.nodes.iter() {
43            if node_matches_call(node, &[def_paths.vec_remove.last_def_id(), def_paths.vec_insert.last_def_id()]) {
44                let index_edge = &graph.edges[node.in_edges[1]];
45                let index_node = &graph.nodes[index_edge.src];
46                if is_0_usize(index_node) {
47                    self.record.push(node.span);
48                }
49            }
50        }
51    }
52
53    fn report(&self, graph: &Graph) {
54        for span in self.record.iter() {
55            report_vec_remove_bug(graph, *span);
56        }
57    }
58
59    fn cnt(&self) -> usize {
60        self.record.len()
61    }
62}
63
64fn report_vec_remove_bug(graph: &Graph, span: Span) {
65    OptReport::from_graph(graph)
66        .title("Improper data collection detected")
67        .annotate(Level::Error, span, "Vec increasement / decreasement happens here.")
68        .footer("Use VecQueue instead of Vec.")
69        .emit();
70}