rapx/check/opt/data_collection/suboptimal/
vec_remove.rs1use 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}