Skip to main content

normalize_languages/
ada.rs

1//! Ada language support.
2
3use crate::docstring::extract_preceding_prefix_comments;
4use crate::{ContainerBody, Import, Language, LanguageSymbols};
5use tree_sitter::Node;
6
7/// Ada language support.
8pub 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        // Ada: with Package;
55        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        // Ada has no dedicated body field; use the container node itself
69        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        // Ada: "package Foo is ... end Foo;" — find `is` child, then `end`
79        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        // Ada uses -- for line comments
84        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            // Type definitions
113            "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            // Declarations
124            "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 and task types
135            "protected_body", "protected_body_stub", "protected_definition", "protected_type_declaration",
136            "task_body", "task_body_stub", "task_definition", "task_type_declaration",
137            // Stubs
138            "package_body_stub", "subprogram_body_stub",
139            // Statements
140            "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            // Expressions
144            "qualified_expression", "raise_expression",
145            // Potentially useful - control flow
146            "exception_handler", "if_statement", "exit_statement", "case_statement",
147            // Representation clauses
148            "at_clause", "attribute_definition_clause", "component_clause", "enumeration_aggregate",
149            "enumeration_representation_clause", "mod_clause", "record_representation_clause",
150            // Control flow and statements
151            "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            // Contracts and aspects
156            "aspect_specification", "global_aspect_definition",
157            // GNAT-specific
158            "gnatprep_declarative_if_statement", "gnatprep_identifier", "gnatprep_if_statement",
159            // Expressions and operators
160            "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            // control flow — not extracted as symbols
168            "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}