qlty_analysis/
lang.rs

1use crate::code::{node_source, File};
2use core::fmt;
3use std::sync::Arc;
4use tree_sitter::{Node, Parser, Query};
5
6mod go;
7mod java;
8mod javascript;
9mod kotlin;
10mod php;
11mod python;
12mod ruby;
13mod rust;
14mod tsx;
15mod typescript;
16mod typescript_common;
17
18pub use {
19    go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, tsx::*,
20    typescript::*,
21};
22
23#[allow(clippy::borrowed_box)]
24pub fn from_str(name: &str) -> Option<&Box<dyn Language + Sync>> {
25    ALL_LANGS.iter().find(|language| language.name() == name)
26}
27
28use lazy_static::lazy_static;
29
30lazy_static! {
31    pub static ref ALL_LANGS: Vec<Box<dyn Language + Sync>> = {
32        vec![
33            Box::<php::Php>::default(),
34            Box::<kotlin::Kotlin>::default(),
35            Box::<go::Go>::default(),
36            Box::<java::Java>::default(),
37            Box::<javascript::JavaScript>::default(),
38            Box::<python::Python>::default(),
39            Box::<ruby::Ruby>::default(),
40            Box::<rust::Rust>::default(),
41            Box::<typescript::TypeScript>::default(),
42            Box::<tsx::TSX>::default(),
43        ]
44    };
45}
46
47pub trait Language {
48    fn name(&self) -> &str;
49
50    fn self_keyword(&self) -> Option<&str>;
51
52    fn invisible_container_nodes(&self) -> Vec<&str> {
53        vec![]
54    }
55    fn if_nodes(&self) -> Vec<&str>;
56    fn elsif_nodes(&self) -> Vec<&str> {
57        vec![]
58    }
59    fn else_nodes(&self) -> Vec<&str> {
60        vec![]
61    }
62    fn ternary_nodes(&self) -> Vec<&str> {
63        vec![]
64    }
65    fn switch_nodes(&self) -> Vec<&str>;
66    fn case_nodes(&self) -> Vec<&str>;
67    fn loop_nodes(&self) -> Vec<&str>;
68    fn except_nodes(&self) -> Vec<&str> {
69        vec![]
70    }
71    fn try_expression_nodes(&self) -> Vec<&str> {
72        vec![]
73    }
74    fn conditional_assignment_nodes(&self) -> Vec<&str> {
75        vec![]
76    }
77    fn jump_nodes(&self) -> Vec<&str>;
78    fn return_nodes(&self) -> Vec<&str>;
79    fn binary_nodes(&self) -> Vec<&str>;
80    fn field_nodes(&self) -> Vec<&str>;
81    fn call_nodes(&self) -> Vec<&str>;
82    fn function_nodes(&self) -> Vec<&str>;
83    fn closure_nodes(&self) -> Vec<&str>;
84    fn comment_nodes(&self) -> Vec<&str>;
85    fn string_nodes(&self) -> Vec<&str>;
86    fn block_nodes(&self) -> Vec<&str> {
87        vec![]
88    }
89
90    fn boolean_operator_nodes(&self) -> Vec<&str>;
91
92    fn constructor_names(&self) -> Vec<&str> {
93        vec![]
94    }
95
96    fn destructor_names(&self) -> Vec<&str> {
97        vec![]
98    }
99
100    fn is_decorator_function(&self, _node: &Node) -> bool {
101        false
102    }
103
104    fn is_instance_method(&self, _file: &File, _node: &Node) -> bool {
105        true
106    }
107
108    fn is_jump_label(&self, _node: &Node) -> bool {
109        false
110    }
111
112    fn all_operators(&self) -> Vec<&str> {
113        vec![]
114    }
115
116    fn all_operands(&self) -> Vec<&str> {
117        vec![]
118    }
119
120    fn iterator_method_identifiers(&self) -> Vec<&str> {
121        vec![]
122    }
123
124    fn call_identifiers(&self, source_file: &File, node: &Node) -> (Option<String>, String);
125    fn field_identifiers(&self, source_file: &File, node: &Node) -> (String, String);
126
127    fn tree_sitter_language(&self) -> tree_sitter::Language;
128
129    fn class_query(&self) -> &Query;
130    fn function_declaration_query(&self) -> &Query;
131    fn field_query(&self) -> &Query;
132    fn implementation_query(&self) -> Option<&Query> {
133        None
134    }
135
136    fn has_labeled_jumps(&self) -> bool {
137        false
138    }
139
140    fn query(&self, query_source: &str) -> Query {
141        Query::new(&self.tree_sitter_language(), query_source).unwrap()
142    }
143
144    fn parser(&self) -> Parser {
145        let mut parser = Parser::new();
146        parser
147            .set_language(&self.tree_sitter_language())
148            .expect("Error loading grammar");
149        parser
150    }
151
152    fn has_field_names(&self) -> bool {
153        false
154    }
155
156    fn sanitize_parameter_name(&self, parameter_name: String) -> Option<String> {
157        if let Some(self_keyword) = self.self_keyword() {
158            if parameter_name != self_keyword
159                && parameter_name != format!("&{}", self_keyword)
160                && parameter_name != format!("&mut {}", self_keyword)
161            {
162                return Some(parameter_name);
163            }
164        }
165        None
166    }
167
168    fn get_parameter_names(
169        &self,
170        parameters_node: tree_sitter::Node,
171        source_file: &Arc<File>,
172    ) -> Vec<String> {
173        let mut parameter_names = vec![];
174        let cursor = &mut parameters_node.walk();
175
176        for parameter_node in parameters_node.named_children(cursor) {
177            let parameter_name = node_source(&parameter_node, &source_file);
178
179            let sanitized_parameter_name = self.sanitize_parameter_name(parameter_name);
180            match sanitized_parameter_name {
181                Some(sanitized_parameter_name) => parameter_names.push(sanitized_parameter_name),
182                _ => {}
183            };
184        }
185        parameter_names
186    }
187
188    fn function_name_node<'a>(&'a self, node: &'a Node) -> Node<'a> {
189        node.child_by_field_name("name").unwrap()
190    }
191}
192
193impl fmt::Display for dyn Language {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        write!(f, "Language[{}]", self.name())
196    }
197}
198
199impl fmt::Debug for dyn Language {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        write!(f, "Language[{}]", self.name())
202    }
203}
204
205#[cfg(test)]
206mod test {
207    use super::*;
208
209    #[test]
210    fn language_names() {
211        let variant = crate::lang::from_str("rust").unwrap();
212        assert_eq!("rust", variant.name());
213
214        let rust = crate::lang::Rust::default();
215        assert_eq!(rust.name(), "rust");
216    }
217
218    #[test]
219    fn language_parser() {
220        crate::lang::Rust::default().parser();
221    }
222}