Skip to main content

rapx/check/opt/data_collection/reallocation/
flatten_collect.rs

1use rustc_middle::ty::TyCtxt;
2
3use crate::{analysis::dataflow::*, check::opt::OptCheck};
4use annotate_snippets::Level;
5use rustc_span::Span;
6
7use crate::check::opt::check_utils::node_matches_call;
8use crate::check::opt::report::OptReport;
9
10crate::def_paths! {
11    flat_map: "std::iter::Iterator::flat_map",
12    flatten: "std::iter::Iterator::flatten",
13    collect: "std::iter::Iterator::collect",
14}
15
16pub struct FlattenCollectCheck {
17    record: Vec<Span>,
18}
19
20impl OptCheck for FlattenCollectCheck {
21    fn new() -> Self {
22        Self { record: Vec::new() }
23    }
24
25    fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
26        let def_paths = DEFPATHS.get_or_init(|| DefPaths::new(tcx));
27        for node in graph.nodes.iter() {
28            if node_matches_call(
29                node,
30                &[
31                    def_paths.flat_map.last_def_id(),
32                    def_paths.flatten.last_def_id(),
33                ],
34            ) {
35                for edge_idx in node.out_edges.iter() {
36                    let dst_idx = graph.edges[*edge_idx].dst;
37                    let dst_node = &graph.nodes[dst_idx];
38                    if node_matches_call(dst_node, &[def_paths.collect.last_def_id()]) {
39                        self.record.push(dst_node.span);
40                    }
41                }
42            }
43        }
44    }
45
46    fn report(&self, graph: &Graph) {
47        for span in self.record.iter() {
48            report_flatten_collect(graph, *span);
49        }
50    }
51
52    fn cnt(&self) -> usize {
53        self.record.len()
54    }
55}
56
57fn report_flatten_collect(graph: &Graph, span: Span) {
58    OptReport::from_graph(graph)
59        .file_name(span)
60        .message_level(Level::Error)
61        .title("Data collection inefficiency detected")
62        .annotate(Level::Error, span, "Flatten then collect.")
63        .footer("Use extend manually.")
64        .emit();
65}