rust_code_analysis/
find.rs1use std::path::PathBuf;
2
3use crate::node::Node;
4
5use crate::dump::*;
6use crate::traits::*;
7
8pub fn find<'a, T: ParserTrait>(parser: &'a T, filters: &[String]) -> Option<Vec<Node<'a>>> {
10 let filters = parser.get_filters(filters);
11 let node = parser.get_root();
12 let mut cursor = node.object().walk();
13 let mut stack = Vec::new();
14 let mut good = Vec::new();
15 let mut children = Vec::new();
16
17 stack.push(node);
18
19 while let Some(node) = stack.pop() {
20 if filters.any(&node) {
21 good.push(node);
22 }
23 cursor.reset(node.object());
24 if cursor.goto_first_child() {
25 loop {
26 children.push(Node::new(cursor.node()));
27 if !cursor.goto_next_sibling() {
28 break;
29 }
30 }
31 for child in children.drain(..).rev() {
32 stack.push(child);
33 }
34 }
35 }
36 Some(good)
37}
38
39pub struct FindCfg {
42 pub path: PathBuf,
44 pub filters: Vec<String>,
46 pub line_start: Option<usize>,
51 pub line_end: Option<usize>,
56}
57
58pub struct Find {
59 _guard: (),
60}
61
62impl Callback for Find {
63 type Res = std::io::Result<()>;
64 type Cfg = FindCfg;
65
66 fn call<T: ParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
67 if let Some(good) = find(parser, &cfg.filters) {
68 if !good.is_empty() {
69 println!("In file {}", cfg.path.to_str().unwrap());
70 for node in good {
71 dump_node(parser.get_code(), &node, 1, cfg.line_start, cfg.line_end)?;
72 }
73 println!();
74 }
75 }
76 Ok(())
77 }
78}