feat(kernel): R4 — Java port with Lombok synthesis, gate passed, default-on

Java joins the native kernel (codegraph-kernel/src/java.rs), mirroring
the wasm extractor's Java paths bug-for-bug: package namespaces,
imports, javadoc, annotations→decorates, type_list inheritance,
static-final constants, enum constants, anonymous classes (including
the TS side's 0-based-line quirk on the extends ref), method_invocation
calls with the this.field unwrap and the Foo.getInstance().bar() chain
encoding (#645/#608), static-member value reads, method-reference
fn-refs (#756), value-reference edges, and the full Lombok member
synthesizer (#912: Getter/Setter/Data/Value/Builder/ToString/
EqualsAndHashCode/Slf4j-family with taken-member dedup). The shared
docstring/textutil modules moved to crate level. Grammar:
tree-sitter-java 0.23.5, with the wasm grammar vendored from the same
tag (parser.c sha-matched) replacing tree-sitter-wasms' 2023-era build.

Gate (plan §4c): extraction sweeps 100% — gson 262/262, retrofit
341/341, dubbo 4,048/4,048 — plus a Java torture fixture in npm test;
full-init dump-diffs byte-identical on gson (49,766 rows), retrofit
(62,735), and dubbo (441,266 rows); all R2/R3 repos re-verified; Linux
container runs all 23 kernel tests green under CODEGRAPH_KERNEL_EXPECT=1.

The gate caught a real cross-language bug: fn-ref dedupe and value-ref
self-target checks must compare node ID STRINGS, not node-table rows —
ids collide for same-(kind, name, line) nodes, which minified one-line
bundles hit routinely (retrofit's website JS exposed it; latent in the
TS/JS walker since R2, never released). Fixed in both walkers.

Benchmark honesty: dubbo fresh-init on an 11-core Mac is ~flat
(parse-loop wall 5,020→4,394ms; total ~11.3s both arms) because that
wall is main-thread-bound (reads + store), not worker-CPU-bound — the
§6 expectation assumed otherwise. Where worker CPU binds the kernel
delivers: dubbo on a 2-CPU/6GB container drops 27.8-28.6s → 22.3-22.8s
(~1.25×). The identified lever for the many-core headline is decoding
kernel buffers directly into store rows (skipping per-node JS object
materialization); the buffer contract already carries everything.

DEFAULT_ROUTED now includes java. Full suite: 2,467 tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Colby McHenry
2026-07-16 23:25:29 -05:00
co-authored by Claude Fable 5
parent c8cca9a601
commit 03d54e47a1
19 changed files with 1828 additions and 30 deletions
+10 -10
View File
@@ -3,7 +3,7 @@
//! src/extraction/tree-sitter.ts; TS-file line references are as of the R2
//! port. Bug-for-bug fidelity is deliberate — fix the TS side first.
use super::util;
use crate::textutil as util;
use super::{
body_of, is_builtin_type, is_literal_receiver, is_react_hoc, is_variable_type,
is_vue_collection_name, Extra, Scope, Walker,
@@ -43,7 +43,7 @@ impl<'t> Walker<'t> {
}
let extra = Extra {
docstring: super::docstring::preceding_docstring(node, self.src),
docstring: crate::docstring::preceding_docstring(node, self.src),
signature: self.signature_of(node),
visibility: self.visibility_of(node),
is_exported: Some(self.is_exported(node)),
@@ -120,7 +120,7 @@ impl<'t> Walker<'t> {
let resolved_body = body_of(node); // skipBodilessClass unset for TS/JS
let name = self.extract_name(node);
let extra = Extra {
docstring: super::docstring::preceding_docstring(node, self.src),
docstring: crate::docstring::preceding_docstring(node, self.src),
visibility: self.visibility_of(node),
is_exported: Some(self.is_exported(node)),
..Extra::default()
@@ -161,7 +161,7 @@ impl<'t> Walker<'t> {
let name = self.extract_name(node);
let extra = Extra {
docstring: super::docstring::preceding_docstring(node, self.src),
docstring: crate::docstring::preceding_docstring(node, self.src),
signature: self.signature_of(node),
visibility: self.visibility_of(node),
is_async: Some(self.is_async(node)),
@@ -187,7 +187,7 @@ impl<'t> Walker<'t> {
pub(super) fn extract_interface(&mut self, node: Node<'t>) {
let name = self.extract_name(node);
let extra = Extra {
docstring: super::docstring::preceding_docstring(node, self.src),
docstring: crate::docstring::preceding_docstring(node, self.src),
is_exported: Some(self.is_exported(node)),
..Extra::default()
};
@@ -209,7 +209,7 @@ impl<'t> Walker<'t> {
let Some(body) = body_of(node) else { return };
let name = self.extract_name(node);
let extra = Extra {
docstring: super::docstring::preceding_docstring(node, self.src),
docstring: crate::docstring::preceding_docstring(node, self.src),
visibility: self.visibility_of(node),
is_exported: Some(self.is_exported(node)),
..Extra::default()
@@ -255,7 +255,7 @@ impl<'t> Walker<'t> {
// --- extractProperty (#808 property-classified class fields) ---------------------
pub(super) fn extract_property(&mut self, node: Node<'t>) -> Option<(u32, String)> {
let docstring = super::docstring::preceding_docstring(node, self.src);
let docstring = crate::docstring::preceding_docstring(node, self.src);
let visibility = self.visibility_of(node);
let is_static = Some(self.is_static(node).unwrap_or(false)); // `?? false` — always present
@@ -296,7 +296,7 @@ impl<'t> Walker<'t> {
pub(super) fn extract_variable(&mut self, node: Node<'t>) {
let is_const = self.is_const_decl(node);
let kind: &'static str = if is_const { "constant" } else { "variable" };
let docstring = super::docstring::preceding_docstring(node, self.src);
let docstring = crate::docstring::preceding_docstring(node, self.src);
let is_exported = self.is_exported(node); // `?? false` — always present
for i in 0..node.named_child_count() {
@@ -807,7 +807,7 @@ impl<'t> Walker<'t> {
return false;
}
let extra = Extra {
docstring: super::docstring::preceding_docstring(node, self.src),
docstring: crate::docstring::preceding_docstring(node, self.src),
is_exported: Some(self.is_exported(node)),
..Extra::default()
};
@@ -858,7 +858,7 @@ impl<'t> Walker<'t> {
"property"
};
let extra = Extra {
docstring: super::docstring::preceding_docstring(child, self.src),
docstring: crate::docstring::preceding_docstring(child, self.src),
signature: Some(self.text(child).to_string()),
qualified_name: Some(format!("{alias_name}::{member_name}")),
..Extra::default()