doc-links(java, kotlin): Javadoc and KDoc references become MENTIONS edges, held until their audit

Java's {@link}, {@linkplain}, @see, @throws and {@value}, and Kotlin's [Name]
links, @see, @throws and @sample, bound the way javadoc and Dokka search for a
member (one resolver for both languages, so a Kotlin doc can name a Java type
and back). The leg (doclink_jvm.c extracts the references and each file's
scope; doc_links_jvm.c resolves them) is ported onto the restacked core:
family rows carry their edge type, resolve() takes the per-file state (none
here). All nine families are held (ships=false) until their held-out audit
passes; the suite ships them through the test seam.

The graph moved under the leg since it was written: a Java field's node is
named by the field alone (no longer by its whole declarator, `MAX = 10`), and
a field named like a method of its class has its own node,
<Owner>.<name>#field, where the method used to take the name. The tests
follow: the expected field names lose the initializer, a changed
initializer is a local change repaired file by file (it renamed the node
before, which forced a full run), and a field that shares its accessor's name
is now an edge target and a source (doc_mentions_jvm_java_families_and_reasons,
doc_mentions_jvm_node_ownership), where both were graph_gap rows.

Measured with the leg's binary (1078036f) and this one on the same input:
- elasticsearch subset (libs/ + server/src/main at f3dc4b0bd3a0, 5,956 files):
  no edge lost; 66 new edges and 7 edges moved onto a field's own #field node;
  81 graph_gap rows gone, no new row, no reason changed. A seeded sample of 8
  of the gone rows read against the source: every new edge is right (a field
  named like its accessor, enum constants, a field's own doc as the source).
- Exposed (Kotlin, c419caaab61f): identical, 896 edges and 371 rows.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-10-10 11:07:37 +02:00
1 parent 0c7ca34419
commit a1190afbb0
10 files changed
+11310 -3

No files matched your search

+3 -1
View File
@@ -387,6 +387,7 @@ EXTRACTION_SRCS = \
$(CBM_DIR)/pdf/pdf_tables.c \
$(CBM_DIR)/pdf/pdf_unicode.c \
$(CBM_DIR)/doclink_go.c \
$(CBM_DIR)/doclink_jvm.c \
$(CBM_DIR)/sql_values.c \
$(CBM_DIR)/helpers.c \
$(CBM_DIR)/cpp_branch_views.c \
@@ -514,6 +515,7 @@ PIPELINE_SRCS = \
src/pipeline/doc_links_rst.c \
src/pipeline/doc_links_adoc.c \
src/pipeline/doc_links_go.c \
src/pipeline/doc_links_jvm.c \
src/pipeline/doc_links_msbuild.c \
src/pipeline/pass_route_nodes.c \
src/pipeline/pass_enrichment.c \
@@ -776,7 +778,7 @@ TEST_DISCOVER_SRCS = \
TEST_GRAPH_BUFFER_SRCS = tests/test_graph_buffer.c
TEST_PIPELINE_SRCS = tests/test_registry.c tests/test_pipeline.c tests/test_pipeline_conventions.c tests/test_pipeline_frozen.c tests/test_importance.c tests/test_cross_repo.c tests/test_fqn.c tests/test_route_canon.c tests/test_path_alias.c tests/test_configlink.c tests/test_doclinks.c tests/test_doc_mentions.c tests/test_doc_links_md.c tests/test_doc_links_pdf.c tests/test_doc_links_rst.c tests/test_doc_links_adoc.c tests/test_doc_mentions_go.c tests/test_infrascan.c tests/test_worker_pool.c tests/test_parallel.c tests/test_index_resilience.c tests/test_index_format.c tests/test_call_reference_contract.c tests/repro/repro_call_scope_usages.c tests/repro/repro_call_argument_usages.c tests/repro/repro_reference_precision.c tests/repro/repro_lexical_binding_precision.c tests/repro/repro_call_argument_matrix_a.c tests/repro/repro_call_argument_matrix_b.c tests/repro/repro_call_node_behaviors.c tests/repro/repro_language_registry.c tests/repro/repro_call_node_manifest.c tests/repro/repro_lsp_ordered_signatures.c tests/repro/repro_lsp_ordered_local.c tests/repro/repro_ts_overload_return_chains.c tests/repro/repro_harness_cleanup.c tests/repro/repro_runner_filter.c
TEST_PIPELINE_SRCS = tests/test_registry.c tests/test_pipeline.c tests/test_pipeline_conventions.c tests/test_pipeline_frozen.c tests/test_importance.c tests/test_cross_repo.c tests/test_fqn.c tests/test_route_canon.c tests/test_path_alias.c tests/test_configlink.c tests/test_doclinks.c tests/test_doc_mentions.c tests/test_doc_links_md.c tests/test_doc_links_pdf.c tests/test_doc_links_rst.c tests/test_doc_links_adoc.c tests/test_doc_mentions_go.c tests/test_doc_mentions_jvm.c tests/test_infrascan.c tests/test_worker_pool.c tests/test_parallel.c tests/test_index_resilience.c tests/test_index_format.c tests/test_call_reference_contract.c tests/repro/repro_call_scope_usages.c tests/repro/repro_call_argument_usages.c tests/repro/repro_reference_precision.c tests/repro/repro_lexical_binding_precision.c tests/repro/repro_call_argument_matrix_a.c tests/repro/repro_call_argument_matrix_b.c tests/repro/repro_call_node_behaviors.c tests/repro/repro_language_registry.c tests/repro/repro_call_node_manifest.c tests/repro/repro_lsp_ordered_signatures.c tests/repro/repro_lsp_ordered_local.c tests/repro/repro_ts_overload_return_chains.c tests/repro/repro_harness_cleanup.c tests/repro/repro_runner_filter.c
TEST_WATCHER_SRCS = tests/test_watcher.c
+10
View File
@@ -190,6 +190,16 @@ static const doclink_lang_t DOCLINK_LANGS[] = {
.scan_scope = cbm_doclink_gomod_scan_scope,
.scope_tag = CBM_DOCLINK_GO_SCOPE_TAG,
.portable_scope = cbm_doclink_go_portable_scope},
{.lang = CBM_LANG_JAVA,
.parse_doc = cbm_doclink_java_parse_doc,
.scan_scope = cbm_doclink_java_scan_scope,
.scope_tag = CBM_DOCLINK_JVM_SCOPE_TAG,
.portable_scope = cbm_doclink_jvm_portable_scope},
{.lang = CBM_LANG_KOTLIN,
.parse_doc = cbm_doclink_kotlin_parse_doc,
.scan_scope = cbm_doclink_kotlin_scan_scope,
.scope_tag = CBM_DOCLINK_JVM_SCOPE_TAG,
.portable_scope = cbm_doclink_jvm_portable_scope},
};
static const doclink_lang_t *doclink_lang(CBMLanguage lang) {
+34
View File
@@ -85,6 +85,16 @@
X(CBM_DOCLINK_CS_INHERITDOC, CBM_LANG_CSHARP, "inheritdoc", false, true, "MENTIONS") \
/* go (doclink_go.c): [Name] doc links; held until its held-out audit passes */ \
X(CBM_DOCLINK_GO_DOC_LINK, CBM_LANG_GO, "doc_link", false, false, "MENTIONS") \
/* java and kotlin (doclink_jvm.c): Javadoc and KDoc; held until their audit passes */ \
X(CBM_DOCLINK_JAVA_LINK, CBM_LANG_JAVA, "link", false, false, "MENTIONS") \
X(CBM_DOCLINK_JAVA_LINKPLAIN, CBM_LANG_JAVA, "linkplain", false, false, "MENTIONS") \
X(CBM_DOCLINK_JAVA_SEE, CBM_LANG_JAVA, "see", false, false, "MENTIONS") \
X(CBM_DOCLINK_JAVA_THROWS, CBM_LANG_JAVA, "throws", false, false, "MENTIONS") \
X(CBM_DOCLINK_JAVA_VALUE, CBM_LANG_JAVA, "value", false, false, "MENTIONS") \
X(CBM_DOCLINK_KT_KDOC_LINK, CBM_LANG_KOTLIN, "kdoc_link", false, false, "MENTIONS") \
X(CBM_DOCLINK_KT_SEE, CBM_LANG_KOTLIN, "see", false, false, "MENTIONS") \
X(CBM_DOCLINK_KT_THROWS, CBM_LANG_KOTLIN, "throws", false, false, "MENTIONS") \
X(CBM_DOCLINK_KT_SAMPLE, CBM_LANG_KOTLIN, "sample", false, false, "MENTIONS") \
/* markdown (doclink_md.c): what a document's text names explicitly */ \
X(CBM_DOCLINK_MD_LINK, CBM_LANG_MARKDOWN, "link", false, true, "MENTIONS") \
X(CBM_DOCLINK_MD_PATH, CBM_LANG_MARKDOWN, "path", false, true, "MENTIONS") \
@@ -427,5 +437,29 @@ bool cbm_doclink_go_parse_ref(const char *raw, size_t len, CBMDocLinkGoRef *out)
/* The Go scope blob (Go files and go.mod files) starts with this tag line. */
#define CBM_DOCLINK_GO_SCOPE_TAG "go1"
/* ── Java and Kotlin (doclink_jvm.c) ───────────────────────────────── */
void cbm_doclink_java_parse_doc(CBMExtractCtx *ctx, const CBMDefinition *def, const char *doc,
uint32_t doc_line);
void cbm_doclink_kotlin_parse_doc(CBMExtractCtx *ctx, const CBMDefinition *def, const char *doc,
uint32_t doc_line);
const char *cbm_doclink_java_scan_scope(CBMExtractCtx *ctx);
const char *cbm_doclink_kotlin_scan_scope(CBMExtractCtx *ctx);
char *cbm_doclink_jvm_portable_scope(const char *scope);
/* Normalize one Java parameter type as written in a declaration or in a
* Javadoc `#member(...)` list: annotations, `final`, type arguments, package
* and outer-type qualifiers and a trailing parameter name are dropped,
* `...` becomes `[]`, array brackets stay. "?" when nothing is left. Writes a
* NUL-terminated string into `out` (truncated at cap) and returns its
* length. */
size_t cbm_doclink_java_norm_type(const char *in, size_t len, char *out, size_t cap);
/* Java and Kotlin files share one scope tag: one resolver indexes both. */
#define CBM_DOCLINK_JVM_SCOPE_TAG "jvm1"
/* The longest reference a Java or Kotlin token may carry: a longer one is cut
* just past this length at extraction and reported as unparseable. */
#define CBM_DOCLINK_JVM_REF_MAX 1000
#endif /* CBM_DOCLINK_H */
File diff suppressed because it is too large. Load diff
+1
View File
@@ -47,6 +47,7 @@ const char *cbm_doclink_reason_name(int reason) {
static const cbm_doclink_resolver_t *const DOCLINK_RESOLVERS[] = {
&cbm_doclink_cs_resolver, &cbm_doclink_md_resolver, &cbm_doclink_pdf_resolver,
&cbm_doclink_rst_resolver, &cbm_doclink_adoc_resolver, &cbm_doclink_go_resolver,
&cbm_doclink_jvm_resolver,
};
enum { DOCLINK_RESOLVER_COUNT = sizeof(DOCLINK_RESOLVERS) / sizeof(DOCLINK_RESOLVERS[0]) };
+1
View File
@@ -296,6 +296,7 @@ void cbm_doclink_cs_test_unit_memo(bool on);
* re-resolves such documents with the edited file. */
bool cbm_doclinks_binds_lines(CBMLanguage lang);
extern const cbm_doclink_resolver_t cbm_doclink_go_resolver;
extern const cbm_doclink_resolver_t cbm_doclink_jvm_resolver;
/* True when `rel_path` is a scope input of some language (scope_input). */
bool cbm_doclinks_is_scope_input(const char *rel_path);
File diff suppressed because it is too large. Load diff
+8 -2
View File
@@ -430,9 +430,15 @@ static inline int dm_reason_lines(const char *db, const char *block) {
* so it is the resolution an audit would ship; doc_links_md_ship_gate tests
* the production gate itself. */
static const int DM_HELD_FAMILIES[] = {
CBM_DOCLINK_MD_BARE_PATH, CBM_DOCLINK_MD_SUPERSEDES_PROSE, CBM_DOCLINK_RST_INCLUDE,
CBM_DOCLINK_RST_KERNEL_DOC, CBM_DOCLINK_ADOC_ATTRIBUTE, CBM_DOCLINK_ADOC_CODE_PATH,
CBM_DOCLINK_MD_BARE_PATH, CBM_DOCLINK_MD_SUPERSEDES_PROSE,
CBM_DOCLINK_RST_INCLUDE, CBM_DOCLINK_RST_KERNEL_DOC,
CBM_DOCLINK_ADOC_ATTRIBUTE, CBM_DOCLINK_ADOC_CODE_PATH,
CBM_DOCLINK_ADOC_CODE_NAME, CBM_DOCLINK_GO_DOC_LINK,
CBM_DOCLINK_JAVA_LINK, CBM_DOCLINK_JAVA_LINKPLAIN,
CBM_DOCLINK_JAVA_SEE, CBM_DOCLINK_JAVA_THROWS,
CBM_DOCLINK_JAVA_VALUE, CBM_DOCLINK_KT_KDOC_LINK,
CBM_DOCLINK_KT_SEE, CBM_DOCLINK_KT_THROWS,
CBM_DOCLINK_KT_SAMPLE,
};
static inline void dm_ship_held_families(void) {
File diff suppressed because it is too large. Load diff
+2
View File
@@ -1826,6 +1826,7 @@ extern void suite_doc_links_pdf(void);
extern void suite_doc_links_rst(void);
extern void suite_doc_links_adoc(void);
extern void suite_doc_mentions_go(void);
extern void suite_doc_mentions_jvm(void);
extern void suite_infrascan(void);
extern void suite_cli(void);
extern void suite_agent_clients(void);
@@ -2298,6 +2299,7 @@ int main(int argc, char **argv) {
RUN_SELECTED_SUITE(doc_links_rst);
RUN_SELECTED_SUITE(doc_links_adoc);
RUN_SELECTED_SUITE(doc_mentions_go);
RUN_SELECTED_SUITE(doc_mentions_jvm);
/* Infrastructure scanning */
RUN_SELECTED_SUITE(infrascan);