• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

igorls / context-builder / 22035105478

15 Feb 2026 11:46AM UTC coverage: 59.277% (-2.8%) from 62.112%
22035105478

push

github

igorls
release: v0.8.1

Bug fixes (Deep Think v6 review — 11 confirmed bugs):
- Fixed cache hash desync (4 missing fields)
- Fixed JS/TS arrow function body leak
- Fixed Python decorator erasure + is_method
- Fixed Rust tuple struct erasure
- Fixed C/C++ header prototype extraction
- Fixed C++ class inheritance byte-slicing
- Fixed JS/TS export signatures for lexical_declaration
- Added .jsx extension support

Dependency updates:
- tree-sitter: 0.24 → 0.26
- tree-sitter-rust: 0.23 → 0.24
- tree-sitter-javascript: 0.23 → 0.25
- tree-sitter-python: 0.23 → 0.25
- tree-sitter-go: 0.23 → 0.25
- tree-sitter-c: 0.23 → 0.24

93 of 292 new or added lines in 11 files covered. (31.85%)

29 existing lines in 3 files now uncovered.

1821 of 3072 relevant lines covered (59.28%)

4.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.72
/src/tree_sitter/languages/cpp.rs
1
//! C++ language support for tree-sitter.
2

3
#[cfg(feature = "tree-sitter-cpp")]
4
use tree_sitter::{Parser, Tree};
5

6
#[cfg(feature = "tree-sitter-cpp")]
7
use crate::tree_sitter::language_support::{
8
    CodeStructure, LanguageSupport, Signature, SignatureKind, Visibility,
9
    slice_signature_before_body,
10
};
11

12
pub struct CppSupport;
13

14
#[cfg(feature = "tree-sitter-cpp")]
15
impl CppSupport {
16
    fn get_language() -> tree_sitter::Language {
1✔
17
        tree_sitter_cpp::LANGUAGE.into()
1✔
18
    }
19
}
20

21
#[cfg(feature = "tree-sitter-cpp")]
22
impl LanguageSupport for CppSupport {
23
    fn file_extensions(&self) -> &[&'static str] {
1✔
24
        &["cpp", "cxx", "cc", "hpp", "hxx", "hh"]
25
    }
26

27
    fn parse(&self, source: &str) -> Option<Tree> {
1✔
28
        let mut parser = Parser::new();
1✔
29
        parser.set_language(&Self::get_language()).ok()?;
2✔
30
        parser.parse(source, None)
1✔
31
    }
32

33
    fn extract_signatures(&self, source: &str, visibility: Visibility) -> Vec<Signature> {
1✔
34
        let tree = match self.parse(source) {
1✔
35
            Some(t) => t,
1✔
36
            None => return Vec::new(),
×
37
        };
38

39
        let root = tree.root_node();
1✔
40
        let mut signatures = Vec::new();
1✔
41

42
        self.extract_signatures_from_node(source, &root, visibility, &mut signatures);
1✔
43

44
        signatures.sort_by_key(|s| s.line_number);
1✔
45
        signatures
1✔
46
    }
47

48
    fn extract_structure(&self, source: &str) -> CodeStructure {
×
49
        let tree = match self.parse(source) {
×
50
            Some(t) => t,
×
51
            None => return CodeStructure::default(),
×
52
        };
53

54
        let root = tree.root_node();
×
55
        let mut structure = CodeStructure {
56
            total_lines: source.lines().count(),
×
57
            ..Default::default()
58
        };
59

60
        self.extract_structure_from_node(&root, &mut structure);
×
61
        structure
×
62
    }
63

64
    fn find_truncation_point(&self, source: &str, max_bytes: usize) -> usize {
×
65
        if source.len() <= max_bytes {
×
66
            return source.len();
×
67
        }
68

69
        let tree = match self.parse(source) {
×
70
            Some(t) => t,
×
71
            None => return max_bytes,
×
72
        };
73

74
        let root = tree.root_node();
×
75
        let mut best_end = 0;
×
76

77
        let mut cursor = root.walk();
×
78
        self.find_best_boundary(&mut cursor, max_bytes, &mut best_end);
×
79
        drop(cursor);
×
80

81
        if best_end == 0 { max_bytes } else { best_end }
×
82
    }
83
}
84

85
#[cfg(feature = "tree-sitter-cpp")]
86
impl CppSupport {
87
    fn extract_signatures_from_node(
1✔
88
        &self,
89
        source: &str,
90
        node: &tree_sitter::Node,
91
        visibility: Visibility,
92
        signatures: &mut Vec<Signature>,
93
    ) {
94
        match node.kind() {
1✔
95
            "function_definition" => {
1✔
96
                if let Some(sig) = self.extract_function_signature(source, node, visibility) {
1✔
97
                    signatures.push(sig);
×
98
                }
99
            }
100
            "declaration" => {
1✔
101
                // Header file prototypes: `int foo(int x, int y);`
NEW
102
                if let Some(sig) = self.extract_declaration_signature(source, node) {
×
NEW
103
                    signatures.push(sig);
×
104
                }
105
            }
106
            "class_specifier" => {
1✔
107
                if let Some(sig) = self.extract_class_signature(source, node, visibility) {
2✔
108
                    signatures.push(sig);
1✔
109
                }
110
            }
111
            "struct_specifier" => {
1✔
112
                if let Some(sig) = self.extract_struct_signature(source, node) {
×
113
                    signatures.push(sig);
×
114
                }
115
            }
116
            "enum_specifier" => {
1✔
117
                if let Some(sig) = self.extract_enum_signature(source, node) {
×
118
                    signatures.push(sig);
×
119
                }
120
            }
121
            "alias_declaration" | "type_definition" => {
2✔
122
                if let Some(sig) = self.extract_alias_signature(source, node) {
×
123
                    signatures.push(sig);
×
124
                }
125
            }
126
            "preproc_function_def" => {
1✔
127
                if let Some(sig) = self.extract_macro_signature(source, node) {
×
128
                    signatures.push(sig);
×
129
                }
130
            }
131
            _ => {}
132
        }
133

134
        let mut cursor = node.walk();
1✔
135
        for child in node.children(&mut cursor) {
2✔
136
            self.extract_signatures_from_node(source, &child, visibility, signatures);
2✔
137
        }
138
    }
139

140
    fn extract_structure_from_node(&self, node: &tree_sitter::Node, structure: &mut CodeStructure) {
×
141
        match node.kind() {
×
142
            "function_definition" => structure.functions += 1,
×
143
            "class_specifier" => structure.classes += 1,
×
144
            "struct_specifier" => structure.structs += 1,
×
145
            "enum_specifier" => structure.enums += 1,
×
146
            "preproc_include" => {
×
147
                structure.imports.push("include".to_string());
×
148
            }
149
            _ => {}
150
        }
151

152
        let mut cursor = node.walk();
×
153
        for child in node.children(&mut cursor) {
×
154
            self.extract_structure_from_node(&child, structure);
×
155
        }
156
    }
157

158
    #[allow(dead_code)]
159
    fn get_visibility(&self, _node: &tree_sitter::Node) -> Visibility {
×
160
        // C++ has access specifiers: public, private, protected
161
        // For simplicity, we check sibling nodes for access specifiers
162
        // This is a simplified check; full implementation would track class context
163
        Visibility::All
164
    }
165

166
    fn extract_function_signature(
1✔
167
        &self,
168
        source: &str,
169
        node: &tree_sitter::Node,
170
        visibility: Visibility,
171
    ) -> Option<Signature> {
172
        let name = self.find_function_name(node, source)?;
1✔
173
        let return_type = self.find_return_type(node, source);
×
NEW
174
        let params = self.find_child_text(node, "parameter_list", source);
×
175

176
        // Use byte-slicing to preserve templates, parameters, and qualifiers
NEW
177
        let full_sig = slice_signature_before_body(source, node, &["compound_statement"])
×
NEW
178
            .unwrap_or_else(|| {
×
NEW
179
                let mut sig = String::new();
×
NEW
180
                if let Some(r) = &return_type {
×
NEW
181
                    sig.push_str(r);
×
NEW
182
                    sig.push(' ');
×
183
                }
NEW
184
                sig.push_str(&name);
×
NEW
185
                if let Some(p) = &params {
×
NEW
186
                    sig.push_str(p);
×
187
                } else {
NEW
188
                    sig.push_str("()");
×
189
                }
NEW
190
                sig
×
191
            });
192

193
        Some(Signature {
×
194
            kind: SignatureKind::Function,
195
            name,
×
NEW
196
            params,
×
197
            return_type,
×
198
            visibility,
199
            line_number: node.start_position().row + 1,
×
200
            full_signature: full_sig,
×
201
        })
202
    }
203

204
    /// Extract function prototype signatures from `declaration` nodes (header files).
NEW
205
    fn extract_declaration_signature(
×
206
        &self,
207
        source: &str,
208
        node: &tree_sitter::Node,
209
    ) -> Option<Signature> {
210
        // Only capture declarations that look like function prototypes
NEW
211
        let mut cursor = node.walk();
×
NEW
212
        let has_function_declarator = node.children(&mut cursor).any(|c| {
×
NEW
213
            if c.kind() == "function_declarator" {
×
NEW
214
                return true;
×
215
            }
NEW
216
            let mut inner = c.walk();
×
NEW
217
            c.children(&mut inner).any(|gc| gc.kind() == "function_declarator")
×
218
        });
219

NEW
220
        if !has_function_declarator {
×
NEW
221
            return None;
×
222
        }
223

NEW
224
        let name = self.find_function_name(node, source)?;
×
NEW
225
        let text = source[node.start_byte()..node.end_byte()].trim_end();
×
NEW
226
        let full_sig = text.trim_end_matches(';').trim_end().to_string();
×
227

NEW
228
        Some(Signature {
×
229
            kind: SignatureKind::Function,
NEW
230
            name,
×
NEW
231
            params: None,
×
NEW
232
            return_type: None,
×
233
            visibility: Visibility::All,
NEW
234
            line_number: node.start_position().row + 1,
×
NEW
235
            full_signature: full_sig,
×
236
        })
237
    }
238
    fn extract_class_signature(
1✔
239
        &self,
240
        source: &str,
241
        node: &tree_sitter::Node,
242
        visibility: Visibility,
243
    ) -> Option<Signature> {
244
        let name = self.find_child_text(node, "type_identifier", source)?;
2✔
245

246
        // Use byte-slicing to preserve templates and inheritance
247
        // e.g., `template<typename T> class Foo : public Base`
248
        let full_sig = slice_signature_before_body(source, node, &["field_declaration_list"])
1✔
249
            .unwrap_or_else(|| format!("class {}", name));
1✔
250

251
        Some(Signature {
1✔
252
            kind: SignatureKind::Class,
253
            name,
1✔
254
            params: None,
1✔
255
            return_type: None,
1✔
256
            visibility,
257
            line_number: node.start_position().row + 1,
2✔
258
            full_signature: full_sig,
1✔
259
        })
260
    }
261

262
    fn extract_struct_signature(
×
263
        &self,
264
        source: &str,
265
        node: &tree_sitter::Node,
266
    ) -> Option<Signature> {
267
        let name = self.find_child_text(node, "type_identifier", source)?;
×
268

269
        let full_sig = format!("struct {}", name);
×
270

271
        Some(Signature {
×
272
            kind: SignatureKind::Struct,
273
            name,
×
274
            params: None,
×
275
            return_type: None,
×
276
            visibility: Visibility::All,
277
            line_number: node.start_position().row + 1,
×
278
            full_signature: full_sig,
×
279
        })
280
    }
281

282
    fn extract_enum_signature(&self, source: &str, node: &tree_sitter::Node) -> Option<Signature> {
×
283
        let name = self.find_child_text(node, "type_identifier", source)?;
×
284

285
        let full_sig = format!("enum {}", name);
×
286

287
        Some(Signature {
×
288
            kind: SignatureKind::Enum,
289
            name,
×
290
            params: None,
×
291
            return_type: None,
×
292
            visibility: Visibility::All,
293
            line_number: node.start_position().row + 1,
×
294
            full_signature: full_sig,
×
295
        })
296
    }
297

298
    fn extract_alias_signature(&self, source: &str, node: &tree_sitter::Node) -> Option<Signature> {
×
299
        let name = self.find_child_text(node, "type_identifier", source)?;
×
300

301
        let full_sig = format!("using/typedef {}", name);
×
302

303
        Some(Signature {
×
304
            kind: SignatureKind::TypeAlias,
305
            name,
×
306
            params: None,
×
307
            return_type: None,
×
308
            visibility: Visibility::All,
309
            line_number: node.start_position().row + 1,
×
310
            full_signature: full_sig,
×
311
        })
312
    }
313

314
    fn extract_macro_signature(&self, source: &str, node: &tree_sitter::Node) -> Option<Signature> {
×
315
        let name = self.find_child_text(node, "identifier", source)?;
×
316

317
        let full_sig = format!("#define {}", name);
×
318

319
        Some(Signature {
×
320
            kind: SignatureKind::Macro,
321
            name,
×
322
            params: None,
×
323
            return_type: None,
×
324
            visibility: Visibility::All,
325
            line_number: node.start_position().row + 1,
×
326
            full_signature: full_sig,
×
327
        })
328
    }
329

330
    fn find_function_name(&self, node: &tree_sitter::Node, source: &str) -> Option<String> {
1✔
331
        let mut cursor = node.walk();
1✔
332
        for child in node.children(&mut cursor) {
2✔
333
            if child.kind() == "function_declarator" || child.kind() == "reference_declarator" {
3✔
334
                let mut inner_cursor = child.walk();
1✔
335
                for inner in child.children(&mut inner_cursor) {
2✔
336
                    if inner.kind() == "identifier" || inner.kind() == "qualified_identifier" {
3✔
337
                        return Some(source[inner.start_byte()..inner.end_byte()].to_string());
×
338
                    }
339
                }
340
            }
341
            if child.kind() == "identifier" || child.kind() == "qualified_identifier" {
3✔
342
                return Some(source[child.start_byte()..child.end_byte()].to_string());
×
343
            }
344
        }
345
        None
1✔
346
    }
347

348
    fn find_return_type(&self, node: &tree_sitter::Node, source: &str) -> Option<String> {
×
349
        let mut cursor = node.walk();
×
350
        for child in node.children(&mut cursor) {
×
351
            match child.kind() {
×
352
                "primitive_type" | "type_identifier" | "sized_type_specifier" => {
×
353
                    return Some(source[child.start_byte()..child.end_byte()].to_string());
×
354
                }
355
                _ => {}
356
            }
357
        }
358
        None
×
359
    }
360

361
    fn find_child_text(
1✔
362
        &self,
363
        node: &tree_sitter::Node,
364
        kind: &str,
365
        source: &str,
366
    ) -> Option<String> {
367
        let mut cursor = node.walk();
1✔
368
        for child in node.children(&mut cursor) {
2✔
369
            if child.kind() == kind {
2✔
370
                return Some(source[child.start_byte()..child.end_byte()].to_string());
1✔
371
            }
372
        }
373
        None
×
374
    }
375

376
    fn find_best_boundary(
×
377
        &self,
378
        cursor: &mut tree_sitter::TreeCursor,
379
        max_bytes: usize,
380
        best_end: &mut usize,
381
    ) {
382
        loop {
383
            let node = cursor.node();
×
384
            let end_byte = node.end_byte();
×
385

386
            if end_byte <= max_bytes && end_byte > *best_end {
×
387
                let is_item = matches!(
×
388
                    node.kind(),
×
389
                    "function_definition"
390
                        | "class_specifier"
391
                        | "struct_specifier"
392
                        | "enum_specifier"
393
                        | "alias_declaration"
394
                        | "type_definition"
395
                );
396
                if is_item {
×
397
                    *best_end = end_byte;
×
398
                }
399
            }
400

401
            if cursor.goto_first_child() {
×
402
                self.find_best_boundary(cursor, max_bytes, best_end);
×
403
                cursor.goto_parent();
×
404
            }
405

406
            if !cursor.goto_next_sibling() {
×
407
                break;
408
            }
409
        }
410
    }
411
}
412

413
#[cfg(test)]
414
mod tests {
415
    use super::*;
416

417
    #[test]
418
    fn test_extract_class_signature() {
419
        let source = r#"
420
class HelloWorld {
421
public:
422
    void greet() {
423
        std::cout << "Hello" << std::endl;
424
    }
425
};
426
"#;
427

428
        let signatures = CppSupport.extract_signatures(source, Visibility::All);
429
        let classes: Vec<_> = signatures
430
            .iter()
431
            .filter(|s| s.kind == SignatureKind::Class)
432
            .collect();
433
        assert!(!classes.is_empty());
434
        assert_eq!(classes[0].name, "HelloWorld");
435
    }
436

437
    #[test]
438
    fn test_file_extensions() {
439
        assert!(CppSupport.supports_extension("cpp"));
440
        assert!(CppSupport.supports_extension("hpp"));
441
        assert!(CppSupport.supports_extension("cxx"));
442
        assert!(!CppSupport.supports_extension("c"));
443
    }
444
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc