Skip to main content

qex_core/chunk/languages/
cpp.rs

1use super::{extract_preceding_comments, find_child_text, find_name, NodeMetadata, LanguageChunker};
2use crate::chunk::ChunkType;
3
4pub struct CppChunker;
5
6impl LanguageChunker for CppChunker {
7    fn tree_sitter_language(&self) -> tree_sitter::Language {
8        tree_sitter_cpp::LANGUAGE.into()
9    }
10
11    fn language_name(&self) -> &str {
12        "cpp"
13    }
14
15    fn file_extensions(&self) -> &[&str] {
16        &["cpp", "cc", "cxx", "hpp", "hh", "hxx"]
17    }
18
19    fn is_splittable(&self, node_type: &str) -> bool {
20        matches!(
21            node_type,
22            "function_definition"
23                | "class_specifier"
24                | "struct_specifier"
25                | "enum_specifier"
26                | "namespace_definition"
27                | "template_declaration"
28        )
29    }
30
31    fn has_nested_chunks(&self, node_type: &str) -> bool {
32        matches!(
33            node_type,
34            "class_specifier" | "struct_specifier" | "namespace_definition" | "template_declaration"
35        )
36    }
37
38    fn classify_node(&self, node_type: &str, parent_name: Option<&str>) -> ChunkType {
39        match node_type {
40            "class_specifier" => ChunkType::Class,
41            "struct_specifier" => ChunkType::Struct,
42            "enum_specifier" => ChunkType::Enum,
43            "namespace_definition" => ChunkType::Namespace,
44            "function_definition" if parent_name.is_some() => ChunkType::Method,
45            "function_definition" => ChunkType::Function,
46            "template_declaration" => ChunkType::Function,
47            _ => ChunkType::ModuleLevel,
48        }
49    }
50
51    fn extract_metadata(&self, node: tree_sitter::Node, source: &str) -> NodeMetadata {
52        let mut meta = NodeMetadata::default();
53
54        match node.kind() {
55            "function_definition" => {
56                let mut cursor = node.walk();
57                for child in node.children(&mut cursor) {
58                    if child.kind() == "function_declarator" {
59                        meta.name = find_name(child, source)
60                            .or_else(|| find_child_text(child, source, "field_identifier"))
61                            .or_else(|| find_child_text(child, source, "destructor_name"));
62                    }
63                }
64                meta.docstring = extract_preceding_comments(node, source);
65            }
66            "class_specifier" | "struct_specifier" | "enum_specifier" => {
67                meta.name = find_child_text(node, source, "type_identifier")
68                    .or_else(|| find_name(node, source));
69                meta.docstring = extract_preceding_comments(node, source);
70            }
71            "namespace_definition" => {
72                meta.name = find_name(node, source);
73                meta.docstring = extract_preceding_comments(node, source);
74            }
75            "template_declaration" => {
76                // Look inside for the actual declaration
77                let mut cursor = node.walk();
78                for child in node.children(&mut cursor) {
79                    if child.kind() == "function_definition" || child.kind() == "class_specifier" {
80                        let inner = self.extract_metadata(child, source);
81                        meta.name = inner.name;
82                        meta.docstring = inner.docstring;
83                        break;
84                    }
85                }
86                if meta.docstring.is_none() {
87                    meta.docstring = extract_preceding_comments(node, source);
88                }
89            }
90            _ => {
91                meta.name = find_name(node, source);
92                meta.docstring = extract_preceding_comments(node, source);
93            }
94        }
95
96        meta
97    }
98}