rapx/check/opt/data_collection/reallocation/
flatten_collect.rs1
2use rustc_middle::ty::TyCtxt;
3
4use crate::{
5 analysis::dataflow::*,
6 check::opt::OptCheck,
7};
8use annotate_snippets::Level;
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 flat_map: "std::iter::Iterator::flat_map",
16 flatten: "std::iter::Iterator::flatten",
17 collect: "std::iter::Iterator::collect",
18}
19
20
21pub struct FlattenCollectCheck {
22 record: Vec<Span>,
23}
24
25impl OptCheck for FlattenCollectCheck {
26 fn new() -> Self {
27 Self { record: Vec::new() }
28 }
29
30 fn check(&mut self, graph: &Graph, tcx: &TyCtxt) {
31 let _ = &DEFPATHS.get_or_init(|| DefPaths::new(tcx));
32 let def_paths = DEFPATHS.get().unwrap();
33 for node in graph.nodes.iter() {
34 if node_matches_call(node, &[def_paths.flat_map.last_def_id(), def_paths.flatten.last_def_id()]) {
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}