1use crate::docstring::extract_preceding_prefix_comments;
4use crate::{ContainerBody, Import, Language, LanguageSymbols};
5use tree_sitter::Node;
6
7pub struct Ada;
9
10impl Language for Ada {
11 fn name(&self) -> &'static str {
12 "Ada"
13 }
14 fn extensions(&self) -> &'static [&'static str] {
15 &["ada", "adb", "ads"]
16 }
17 fn grammar_name(&self) -> &'static str {
18 "ada"
19 }
20
21 fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
22 Some(self)
23 }
24
25 fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
26 match node.kind() {
27 "with_clause" => {
28 let text = &content[node.byte_range()];
29 vec![Import {
30 module: text.trim().to_string(),
31 names: Vec::new(),
32 alias: None,
33 is_wildcard: false,
34 is_relative: false,
35 line: node.start_position().row + 1,
36 }]
37 }
38 "use_clause" => {
39 let text = &content[node.byte_range()];
40 vec![Import {
41 module: text.trim().to_string(),
42 names: Vec::new(),
43 alias: None,
44 is_wildcard: true,
45 is_relative: false,
46 line: node.start_position().row + 1,
47 }]
48 }
49 _ => Vec::new(),
50 }
51 }
52
53 fn format_import(&self, import: &Import, _names: Option<&[&str]>) -> String {
54 format!("with {};", import.module)
56 }
57
58 fn is_test_symbol(&self, symbol: &crate::Symbol) -> bool {
59 let name = symbol.name.as_str();
60 match symbol.kind {
61 crate::SymbolKind::Function | crate::SymbolKind::Method => name.starts_with("test_"),
62 crate::SymbolKind::Module => name == "tests" || name == "test",
63 _ => false,
64 }
65 }
66
67 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
68 Some(*node)
70 }
71
72 fn analyze_container_body(
73 &self,
74 body_node: &Node,
75 content: &str,
76 inner_indent: &str,
77 ) -> Option<ContainerBody> {
78 crate::body::analyze_is_begin_end_body(body_node, content, inner_indent)
80 }
81
82 fn extract_docstring(&self, node: &Node, content: &str) -> Option<String> {
83 extract_preceding_prefix_comments(node, content, "--")
85 }
86
87 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
88 if let Some(name_node) = node.child_by_field_name("name") {
89 return Some(&content[name_node.byte_range()]);
90 }
91 let mut cursor = node.walk();
92 for child in node.children(&mut cursor) {
93 if child.kind() == "identifier" || child.kind() == "defining_identifier" {
94 return Some(&content[child.byte_range()]);
95 }
96 }
97 None
98 }
99}
100
101impl LanguageSymbols for Ada {}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::validate_unused_kinds_audit;
107
108 #[test]
109 fn unused_node_kinds_audit() {
110 #[rustfmt::skip]
111 let documented_unused: &[&str] = &[
112 "access_definition", "access_to_object_definition", "access_to_subprogram_definition",
114 "array_type_definition", "decimal_fixed_point_definition", "derived_type_definition",
115 "enumeration_type_definition", "floating_point_definition", "formal_access_type_definition",
116 "formal_array_type_definition", "formal_decimal_fixed_point_definition",
117 "formal_derived_type_definition", "formal_discrete_type_definition",
118 "formal_floating_point_definition", "formal_interface_type_definition",
119 "formal_modular_type_definition", "formal_ordinary_fixed_point_definition",
120 "formal_private_type_definition", "formal_signed_integer_type_definition",
121 "interface_type_definition", "modular_type_definition", "ordinary_fixed_point_definition",
122 "record_type_definition", "signed_integer_type_definition",
123 "body_stub", "component_declaration", "component_definition", "discriminant_specification",
125 "discriminant_specification_list", "entry_declaration", "exception_declaration",
126 "formal_abstract_subprogram_declaration", "formal_complete_type_declaration",
127 "formal_concrete_subprogram_declaration", "formal_incomplete_type_declaration",
128 "formal_object_declaration", "formal_package_declaration", "formal_subprogram_declaration",
129 "generic_formal_part", "generic_renaming_declaration", "generic_subprogram_declaration",
130 "null_procedure_declaration", "number_declaration", "object_declaration",
131 "object_renaming_declaration", "package_renaming_declaration", "parameter_specification",
132 "private_extension_declaration", "single_protected_declaration", "single_task_declaration",
133 "subprogram_renaming_declaration", "subtype_declaration",
134 "protected_body", "protected_body_stub", "protected_definition", "protected_type_declaration",
136 "task_body", "task_body_stub", "task_definition", "task_type_declaration",
137 "package_body_stub", "subprogram_body_stub",
139 "abort_statement", "accept_statement", "assignment_statement", "case_statement_alternative",
141 "delay_relative_statement", "delay_until_statement", "goto_statement", "null_statement",
142 "procedure_call_statement", "raise_statement", "requeue_statement", "simple_return_statement",
143 "qualified_expression", "raise_expression",
145 "exception_handler", "if_statement", "exit_statement", "case_statement",
147 "at_clause", "attribute_definition_clause", "component_clause", "enumeration_aggregate",
149 "enumeration_representation_clause", "mod_clause", "record_representation_clause",
150 "asynchronous_select", "conditional_entry_call", "entry_body", "entry_barrier",
152 "entry_call_alternative", "entry_index_specification", "extended_return_object_declaration",
153 "extended_return_statement", "handled_sequence_of_statements", "loop_label",
154 "loop_parameter_specification", "timed_entry_call",
155 "aspect_specification", "global_aspect_definition",
157 "gnatprep_declarative_if_statement", "gnatprep_identifier", "gnatprep_if_statement",
159 "binary_adding_operator", "choice_parameter_specification", "chunk_specification",
161 "elsif_expression_item", "elsif_statement_item", "exception_choice", "exception_choice_list",
162 "exception_renaming_declaration", "expression", "formal_part", "function_call",
163 "general_access_modifier", "index_subtype_definition",
164 "iterator_specification", "multiplying_operator", "quantifier",
165 "real_range_specification", "record_definition", "reduction_specification",
166 "relational_operator", "subpool_specification", "unary_adding_operator",
167 "declare_expression",
169 "if_expression",
170 "quantified_expression",
171 "block_statement",
172 "loop_statement",
173 "case_expression",
174 "with_clause",
175 "case_expression_alternative",
176 "use_clause",
177 ];
178 validate_unused_kinds_audit(&Ada, documented_unused)
179 .expect("Ada unused node kinds audit failed");
180 }
181}