rapx 0.7.31

A static analysis platform for Rust program analysis and verification
use annotate_snippets::Level;


use crate::{
    analysis::dataflow::*,
    check::opt::OptCheck,
};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;

use crate::check::opt::report::OptReport;
use crate::check::opt::check_utils::node_matches_call;

crate::def_paths! {
    vec_remove: "std::vec::Vec::remove",
    vec_insert: "std::vec::Vec::insert",
}


pub struct VecRemoveCheck {
    record: Vec<Span>,
}

fn is_0_usize(node: &GraphNode) -> bool {
    for op in node.ops.iter() {
        if let NodeOp::Const(desc, _) = op {
            if desc.eq("0_usize") {
                return true;
            }
        }
    }
    false
}

impl OptCheck for VecRemoveCheck {
    fn new() -> Self {
        Self { record: vec![] }
    }

    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
        let def_paths = &DEFPATHS.get_or_init(|| DefPaths::new(tcx));
        for node in graph.nodes.iter() {
            if node_matches_call(node, &[def_paths.vec_remove.last_def_id(), def_paths.vec_insert.last_def_id()]) {
                let index_edge = &graph.edges[node.in_edges[1]];
                let index_node = &graph.nodes[index_edge.src];
                if is_0_usize(index_node) {
                    self.record.push(node.span);
                }
            }
        }
    }

    fn report(&self, graph: &Graph) {
        for span in self.record.iter() {
            report_vec_remove_bug(graph, *span);
        }
    }

    fn cnt(&self) -> usize {
        self.record.len()
    }
}

fn report_vec_remove_bug(graph: &Graph, span: Span) {
    OptReport::from_graph(graph)
        .title("Improper data collection detected")
        .annotate(Level::Error, span, "Vec increasement / decreasement happens here.")
        .footer("Use VecQueue instead of Vec.")
        .emit();
}