qlty_analysis/code/
query.rs

1use crate::code::{File, NodeFilter};
2use tree_sitter::{Node, Query};
3
4pub const QUERY_MATCH_LIMIT: usize = 256;
5
6pub fn matches_count(query: &Query, node: &Node, capture_name: &str, filter: &NodeFilter) -> usize {
7    let mut cursor = tree_sitter::QueryCursor::new();
8    cursor.set_match_limit(QUERY_MATCH_LIMIT as u32);
9    let all_matches = cursor.matches(query, *node, "".as_bytes());
10
11    let mut count = 0;
12
13    for each_match in all_matches {
14        let capture = capture_by_name(query, capture_name, &each_match);
15        let node = capture.node;
16
17        if !filter.exclude(&node) {
18            count += 1;
19        }
20    }
21
22    count
23}
24
25pub fn all_captured_nodes<'a>(
26    query_source: &'a str,
27    source_file: &'a File,
28    node: &'a Node,
29) -> Vec<Node<'a>> {
30    let query_with_capture = format!("{} @the-capture", query_source);
31    let query = source_file.query(&query_with_capture);
32
33    let mut cursor = tree_sitter::QueryCursor::new();
34    cursor.set_match_limit(QUERY_MATCH_LIMIT as u32);
35
36    cursor
37        .matches(&query, *node, source_file.contents.as_bytes())
38        .flat_map(|each_match| each_match.captures)
39        .map(|capture| capture.node)
40        .collect()
41}
42
43pub fn capture_source<'a>(
44    query: &'a Query,
45    name: &'a str,
46    query_match: &'a tree_sitter::QueryMatch,
47    source_file: &File,
48) -> String {
49    let capture = capture_by_name(query, name, query_match);
50    node_source(&capture.node, source_file)
51}
52
53pub fn child_source(parent: &tree_sitter::Node, name: &str, source_file: &File) -> String {
54    let child = parent.child_by_field_name(name).unwrap();
55    node_source(&child, source_file)
56}
57
58pub fn node_source(node: &tree_sitter::Node, source_file: &File) -> String {
59    node.utf8_text(source_file.contents.as_bytes())
60        .unwrap()
61        .to_string()
62}
63
64pub fn capture_by_name_option<'a>(
65    query: &'a Query,
66    name: &'a str,
67    query_match: &'a tree_sitter::QueryMatch,
68) -> Option<&'a tree_sitter::QueryCapture<'a>> {
69    let index = query.capture_index_for_name(name)?;
70
71    query_match
72        .captures
73        .iter()
74        .find(|capture| capture.index == index)
75}
76
77pub fn capture_by_name<'a>(
78    query: &'a Query,
79    name: &'a str,
80    query_match: &'a tree_sitter::QueryMatch,
81) -> &'a tree_sitter::QueryCapture<'a> {
82    let index = query.capture_index_for_name(name).unwrap();
83
84    query_match
85        .captures
86        .iter()
87        .find(|capture| capture.index == index)
88        .unwrap()
89}