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

igorls / context-builder / 26981868037

04 Jun 2026 09:53PM UTC coverage: 78.893% (+1.1%) from 77.785%
26981868037

Pull #1

github

web-flow
Merge b0229f5f3 into 87657bf69
Pull Request #1: v0.9.0 — Trustworthy Output: accurate tokens, honest features, pipe output

220 of 246 new or added lines in 12 files covered. (89.43%)

22 existing lines in 2 files now uncovered.

2538 of 3217 relevant lines covered (78.89%)

4.35 hits per line

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

76.77
/src/tree_sitter/languages/java.rs
1
//! Java language support for tree-sitter.
2

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

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

12
pub struct JavaSupport;
13

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

21
#[cfg(feature = "tree-sitter-java")]
22
impl LanguageSupport for JavaSupport {
23
    fn file_extensions(&self) -> &[&'static str] {
1✔
24
        &["java"]
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);
3✔
45
        signatures
1✔
46
    }
47

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

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

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

64
    fn find_truncation_point(&self, source: &str, max_bytes: usize) -> usize {
1✔
65
        if source.len() <= max_bytes {
1✔
66
            return source.len();
1✔
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-java")]
86
impl JavaSupport {
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
            "method_declaration" => {
1✔
96
                if let Some(sig) = self.extract_method_signature(source, node, visibility) {
2✔
97
                    signatures.push(sig);
1✔
98
                }
99
            }
100
            "class_declaration" => {
1✔
101
                if let Some(sig) = self.extract_class_signature(source, node, visibility) {
2✔
102
                    signatures.push(sig);
1✔
103
                }
104
            }
105
            "interface_declaration" => {
1✔
106
                if let Some(sig) = self.extract_interface_signature(source, node, visibility) {
2✔
107
                    signatures.push(sig);
1✔
108
                }
109
            }
110
            "enum_declaration" => {
1✔
111
                if let Some(sig) = self.extract_enum_signature(source, node, visibility) {
2✔
112
                    signatures.push(sig);
1✔
113
                }
114
            }
115
            "field_declaration" => {
1✔
116
                if let Some(sig) = self.extract_field_signature(source, node, visibility) {
×
117
                    signatures.push(sig);
×
118
                }
119
            }
120
            _ => {}
121
        }
122

123
        let mut cursor = node.walk();
1✔
124
        for child in node.children(&mut cursor) {
2✔
125
            self.extract_signatures_from_node(source, &child, visibility, signatures);
2✔
126
        }
127
    }
128

129
    fn extract_structure_from_node(&self, node: &tree_sitter::Node, structure: &mut CodeStructure) {
1✔
130
        match node.kind() {
1✔
131
            "method_declaration" => structure.functions += 1,
3✔
132
            "class_declaration" => structure.classes += 1,
3✔
133
            "interface_declaration" => structure.interfaces += 1,
3✔
134
            "enum_declaration" => structure.enums += 1,
3✔
135
            "import_declaration" => {
1✔
136
                structure.imports.push("import".to_string());
1✔
137
            }
138
            _ => {}
139
        }
140

141
        let mut cursor = node.walk();
1✔
142
        for child in node.children(&mut cursor) {
2✔
143
            self.extract_structure_from_node(&child, structure);
2✔
144
        }
145
    }
146

147
    /// Determine a Java declaration's visibility from its `modifiers` child.
148
    /// `public` → Public; `private`/`protected` and package-private (no modifier)
149
    /// → Private. This keeps `--visibility public` scoped to the true public API
150
    /// surface and `--visibility private` to everything else.
151
    fn get_visibility(&self, node: &tree_sitter::Node, source: &str) -> Visibility {
1✔
152
        let mut cursor = node.walk();
1✔
153
        for child in node.children(&mut cursor) {
2✔
154
            if child.kind() == "modifiers" {
2✔
155
                let text = &source[child.start_byte()..child.end_byte()];
1✔
156
                if text.split_whitespace().any(|t| t == "public") {
3✔
157
                    return Visibility::Public;
1✔
158
                }
159
                return Visibility::Private;
1✔
160
            }
161
        }
162
        // No modifiers node → package-private, treated as non-public.
163
        Visibility::Private
1✔
164
    }
165

166
    fn extract_method_signature(
1✔
167
        &self,
168
        source: &str,
169
        node: &tree_sitter::Node,
170
        visibility: Visibility,
171
    ) -> Option<Signature> {
172
        let vis = self.get_visibility(node, source);
1✔
173

174
        if visibility == Visibility::Public && vis != Visibility::Public {
2✔
175
            return None;
1✔
176
        }
177
        if visibility == Visibility::Private && vis == Visibility::Public {
2✔
178
            return None;
1✔
179
        }
180

181
        let name = self.find_child_text(node, "identifier", source)?;
2✔
182
        let params = self.find_child_text(node, "formal_parameters", source);
2✔
183
        let return_type = self
184
            .find_child_text(node, "type_identifier", source)
1✔
185
            .or_else(|| self.find_child_text_for_type(node, source));
3✔
186

187
        // Use byte-slicing to preserve annotations, generics, throws, and modifiers
188
        let full_sig = slice_signature_before_body(source, node, &["block"]).unwrap_or_else(|| {
3✔
189
            let mut sig = String::new();
1✔
190
            if vis == Visibility::Public {
2✔
191
                sig.push_str("public ");
×
192
            }
193
            if let Some(r) = &return_type {
2✔
194
                sig.push_str(r);
2✔
195
                sig.push(' ');
1✔
196
            }
197
            sig.push_str(&name);
2✔
198
            if let Some(p) = &params {
1✔
199
                sig.push_str(p);
2✔
200
            } else {
201
                sig.push_str("()");
×
202
            }
203
            sig
1✔
204
        });
205

206
        Some(Signature {
1✔
207
            kind: SignatureKind::Method,
208
            name,
1✔
209
            params,
1✔
210
            return_type,
1✔
211
            visibility: vis,
212
            line_number: node.start_position().row + 1,
2✔
213
            full_signature: full_sig,
1✔
214
        })
215
    }
216

217
    fn extract_class_signature(
1✔
218
        &self,
219
        source: &str,
220
        node: &tree_sitter::Node,
221
        visibility: Visibility,
222
    ) -> Option<Signature> {
223
        let vis = self.get_visibility(node, source);
1✔
224

225
        if visibility == Visibility::Public && vis != Visibility::Public {
2✔
226
            return None;
×
227
        }
228
        if visibility == Visibility::Private && vis == Visibility::Public {
2✔
229
            return None;
1✔
230
        }
231

232
        let name = self.find_child_text(node, "identifier", source)?;
2✔
233

234
        let mut full_sig = String::new();
1✔
235
        if vis == Visibility::Public {
2✔
236
            full_sig.push_str("public ");
1✔
237
        }
238
        full_sig.push_str("class ");
1✔
239
        full_sig.push_str(&name);
1✔
240

241
        Some(Signature {
1✔
242
            kind: SignatureKind::Class,
243
            name,
1✔
244
            params: None,
1✔
245
            return_type: None,
1✔
246
            visibility: vis,
247
            line_number: node.start_position().row + 1,
2✔
248
            full_signature: full_sig,
1✔
249
        })
250
    }
251

252
    fn extract_interface_signature(
1✔
253
        &self,
254
        source: &str,
255
        node: &tree_sitter::Node,
256
        visibility: Visibility,
257
    ) -> Option<Signature> {
258
        let vis = self.get_visibility(node, source);
1✔
259

260
        if visibility == Visibility::Public && vis != Visibility::Public {
1✔
261
            return None;
×
262
        }
263
        if visibility == Visibility::Private && vis == Visibility::Public {
1✔
264
            return None;
×
265
        }
266

267
        let name = self.find_child_text(node, "identifier", source)?;
2✔
268

269
        let mut full_sig = String::new();
1✔
270
        if vis == Visibility::Public {
2✔
271
            full_sig.push_str("public ");
1✔
272
        }
273
        full_sig.push_str("interface ");
1✔
274
        full_sig.push_str(&name);
1✔
275

276
        Some(Signature {
1✔
277
            kind: SignatureKind::Interface,
278
            name,
1✔
279
            params: None,
1✔
280
            return_type: None,
1✔
281
            visibility: vis,
282
            line_number: node.start_position().row + 1,
2✔
283
            full_signature: full_sig,
1✔
284
        })
285
    }
286

287
    fn extract_enum_signature(
1✔
288
        &self,
289
        source: &str,
290
        node: &tree_sitter::Node,
291
        visibility: Visibility,
292
    ) -> Option<Signature> {
293
        let vis = self.get_visibility(node, source);
1✔
294

295
        if visibility == Visibility::Public && vis != Visibility::Public {
1✔
296
            return None;
×
297
        }
298
        if visibility == Visibility::Private && vis == Visibility::Public {
1✔
299
            return None;
×
300
        }
301

302
        let name = self.find_child_text(node, "identifier", source)?;
2✔
303

304
        let mut full_sig = String::new();
1✔
305
        if vis == Visibility::Public {
2✔
306
            full_sig.push_str("public ");
1✔
307
        }
308
        full_sig.push_str("enum ");
1✔
309
        full_sig.push_str(&name);
1✔
310

311
        Some(Signature {
1✔
312
            kind: SignatureKind::Enum,
313
            name,
1✔
314
            params: None,
1✔
315
            return_type: None,
1✔
316
            visibility: vis,
317
            line_number: node.start_position().row + 1,
2✔
318
            full_signature: full_sig,
1✔
319
        })
320
    }
321

322
    fn extract_field_signature(
×
323
        &self,
324
        source: &str,
325
        node: &tree_sitter::Node,
326
        visibility: Visibility,
327
    ) -> Option<Signature> {
NEW
328
        let vis = self.get_visibility(node, source);
×
329

330
        if visibility == Visibility::Public && vis != Visibility::Public {
×
331
            return None;
×
332
        }
333
        if visibility == Visibility::Private && vis == Visibility::Public {
×
334
            return None;
×
335
        }
336

337
        let name = self.find_child_text(node, "identifier", source)?;
×
338
        let full_signature = format!("field {}", &name);
×
339

340
        Some(Signature {
×
341
            kind: SignatureKind::Constant,
342
            name,
×
343
            params: None,
×
344
            return_type: None,
×
345
            visibility: vis,
346
            line_number: node.start_position().row + 1,
×
347
            full_signature,
×
348
        })
349
    }
350

351
    fn find_child_text(
1✔
352
        &self,
353
        node: &tree_sitter::Node,
354
        kind: &str,
355
        source: &str,
356
    ) -> Option<String> {
357
        let mut cursor = node.walk();
1✔
358
        for child in node.children(&mut cursor) {
2✔
359
            if child.kind() == kind {
2✔
360
                return Some(source[child.start_byte()..child.end_byte()].to_string());
1✔
361
            }
362
        }
363
        None
1✔
364
    }
365

366
    fn find_child_text_for_type(&self, node: &tree_sitter::Node, source: &str) -> Option<String> {
1✔
367
        let mut cursor = node.walk();
1✔
368
        for child in node.children(&mut cursor) {
2✔
369
            if child.kind() == "void_type"
2✔
370
                || child.kind() == "integral_type"
2✔
371
                || child.kind() == "boolean_type"
1✔
372
            {
373
                return Some(source[child.start_byte()..child.end_byte()].to_string());
2✔
374
            }
375
        }
376
        None
1✔
377
    }
378

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

389
            if end_byte <= max_bytes && end_byte > *best_end {
×
390
                let is_item = matches!(
×
391
                    node.kind(),
×
392
                    "method_declaration"
393
                        | "class_declaration"
394
                        | "interface_declaration"
395
                        | "enum_declaration"
396
                );
397
                if is_item {
×
398
                    *best_end = end_byte;
×
399
                }
400
            }
401

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

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

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

418
    #[test]
419
    fn test_extract_class_signature() {
420
        let source = r#"
421
public class HelloWorld {
422
    public static void main(String[] args) {
423
        System.out.println("Hello");
424
    }
425
}
426
}
427
"#;
428

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

438
    #[test]
439
    fn test_extract_method_signature() {
440
        let source = r#"
441
public class Calculator {
442
    public int add(int a, int b) {
443
        return a + b;
444
    }
445

446
    private double multiply(double x, double y) {
447
        return x * y;
448
    }
449
}
450
"#;
451

452
        let signatures = JavaSupport.extract_signatures(source, Visibility::All);
453
        let methods: Vec<_> = signatures
454
            .iter()
455
            .filter(|s| s.kind == SignatureKind::Method || s.kind == SignatureKind::Function)
456
            .collect();
457
        assert!(methods.len() >= 2);
458
    }
459

460
    #[test]
461
    fn test_extract_interface_signature() {
462
        let source = r#"
463
public interface Printable {
464
    void print();
465
    String format(String template);
466
}
467
"#;
468

469
        let signatures = JavaSupport.extract_signatures(source, Visibility::All);
470
        let interfaces: Vec<_> = signatures
471
            .iter()
472
            .filter(|s| s.kind == SignatureKind::Interface)
473
            .collect();
474
        assert!(!interfaces.is_empty());
475
        assert_eq!(interfaces[0].name, "Printable");
476
    }
477

478
    #[test]
479
    fn test_extract_enum_signature() {
480
        let source = r#"
481
public enum Color {
482
    RED, GREEN, BLUE;
483
}
484
"#;
485

486
        let signatures = JavaSupport.extract_signatures(source, Visibility::All);
487
        let enums: Vec<_> = signatures
488
            .iter()
489
            .filter(|s| s.kind == SignatureKind::Enum)
490
            .collect();
491
        assert!(!enums.is_empty());
492
        assert_eq!(enums[0].name, "Color");
493
    }
494

495
    #[test]
496
    fn test_extract_class_with_inheritance() {
497
        let source = r#"
498
public class Dog extends Animal implements Runnable {
499
    public void run() {}
500
}
501
"#;
502

503
        let signatures = JavaSupport.extract_signatures(source, Visibility::All);
504
        let classes: Vec<_> = signatures
505
            .iter()
506
            .filter(|s| s.kind == SignatureKind::Class)
507
            .collect();
508
        assert!(!classes.is_empty());
509
        assert_eq!(classes[0].name, "Dog");
510
    }
511

512
    #[test]
513
    fn test_visibility_public_filter() {
514
        // Regression: get_visibility returned All unconditionally, so the
515
        // `public` filter dropped every symbol.
516
        let source = r#"
517
public class Api {
518
    public int publicMethod() { return 1; }
519
    private int privateMethod() { return 2; }
520
    int packageMethod() { return 3; }
521
}
522
"#;
523

524
        let public_only = JavaSupport.extract_signatures(source, Visibility::Public);
525
        assert!(public_only.iter().any(|s| s.name == "publicMethod"));
526
        assert!(
527
            !public_only.iter().any(|s| s.name == "privateMethod"),
528
            "private method leaked into `public` filter"
529
        );
530
        assert!(
531
            !public_only.iter().any(|s| s.name == "packageMethod"),
532
            "package-private method leaked into `public` filter"
533
        );
534
    }
535

536
    #[test]
537
    fn test_visibility_private_filter_excludes_public() {
538
        let source = r#"
539
public class Api {
540
    public int publicMethod() { return 1; }
541
    private int privateMethod() { return 2; }
542
}
543
"#;
544

545
        let private_only = JavaSupport.extract_signatures(source, Visibility::Private);
546
        assert!(private_only.iter().any(|s| s.name == "privateMethod"));
547
        assert!(
548
            !private_only.iter().any(|s| s.name == "publicMethod"),
549
            "public method leaked into `private` filter"
550
        );
551
        assert!(
552
            !private_only.iter().any(|s| s.name == "Api"),
553
            "public class leaked into `private` filter"
554
        );
555
    }
556

557
    #[test]
558
    fn test_extract_structure() {
559
        let source = r#"
560
import java.util.List;
561
import java.util.Map;
562

563
public class App {
564
    public void doStuff() {}
565
    private void helper() {}
566
}
567

568
interface Printable {
569
    void print();
570
}
571

572
enum Status { ACTIVE, INACTIVE }
573
"#;
574

575
        let structure = JavaSupport.extract_structure(source);
576
        assert!(structure.functions >= 2);
577
        assert!(structure.classes >= 1);
578
        assert!(structure.interfaces >= 1);
579
        assert!(structure.enums >= 1);
580
        assert!(structure.imports.len() >= 2);
581
    }
582

583
    #[test]
584
    fn test_parse_valid_java() {
585
        let source = "public class Main { public static void main(String[] args) {} }";
586
        let tree = JavaSupport.parse(source);
587
        assert!(tree.is_some());
588
    }
589

590
    #[test]
591
    fn test_find_truncation_point() {
592
        let source = "public class Main { public static void main(String[] args) {} }";
593
        let point = JavaSupport.find_truncation_point(source, 1000);
594
        assert_eq!(point, source.len());
595
    }
596

597
    #[test]
598
    fn test_file_extensions() {
599
        assert!(JavaSupport.supports_extension("java"));
600
        assert!(!JavaSupport.supports_extension("rs"));
601
    }
602
}
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