Repository navigation
fix(doc-links): report a path::member reference to a missing member (#2587) - #2601
Conversation
…eusData#2587) A Markdown reference `path::member` whose member the code file does not define became an exact MENTIONS edge to the file. A renamed or deleted definition therefore looked like a valid, coarser link instead of a stale reference, and nothing recorded that the member was not found. mdr_segment now says how a member lookup ended. When a code file does not define the member, the reference is an unresolved `missing` row, the same doc-rot reason a missing path gets. When the file defines the name more than once and no owner picks one, it is `ambiguous`. This matches the C resolver, which reports a missing member of an existing type as missing rather than falling back to the type. A member written on a non-code file (a document's heading) keeps the file edge, since those are not graph definitions. Line ranges without a member are unchanged. Test (tests/test_doc_links_md.c) indexes a fixture with a found member, a member reached through its owner, a missing member, a name defined twice, and a member of a Markdown file. Without the fix it fails on the defect: the section's MENTIONS edge to src/util/rounding.py exists (1, expected 0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Scott Beck <296871+bline@users.noreply.github.com>
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
|
Thanks for the clear missing-versus-ambiguous examples and regression coverage. I have read the proposal to use unresolved rows instead of a file fallback; it remains pending review, including the representation choice you called out. |
…usData#2587) A `path::member` reference became a missing row whenever the member lookup found no definition node, but real documentation names members the file has without a node the lookup binds: a call form (`src/util.py::clamp()`), a C macro or a prototype in a header, a TypeScript namespace, a Python enum member, an annotated class attribute. Those lost their correct file edge and were counted as doc rot. A member now reads without a trailing call form, so `clamp()` binds `clamp`. When no definition matches, the resolver reads the code file and calls the member missing only when the file does not write its name at all (a whole identifier, case-sensitive); a member the file writes keeps the file edge it had before. A file that cannot be read whole makes no claim. Ambiguous members are unchanged. Test: doc_links_md_member_written_issue2587 indexes each shape under its own heading, and two members that stay missing (Color::BLUE, which the file writes only as LIGHT_BLUE and a lowercase "blue", and no_such_function). On the previous head all seven shapes are missing rows; without the call-form trim the call form is; without the identifier boundary, or with a case-insensitive match, BLUE takes the file edge. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…ed file (DeusData#2587) An unresolved `path::member` row (missing or ambiguous) leads to its file by no edge, so an incremental run never re-resolved the document when that file changed. Two edits then left a row where a full index has an edge: a body edit that writes a missing member's name (no definition added), and a same-named pair of methods shrinking to one (the name stays, so no removed name reaches the rows). The closure now also takes the files whose missing or ambiguous rows with "::" name a changed or deleted file, matched by base name since a reference may be written relative to the document or to the root. When memory runs out, every such row's file is taken. Test: doc_links_md_member_missing_incremental requires incremental == full on the closure-repair route for both edits and for dropping the name again. Without the new closure rule the "member written" step diverges; with it limited to missing rows the "group shrinks" step does. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
|
Thank you @bline for this fix and for the reproduce-first test. You were right that a
Your |
…eusData#2587) The "group shrinks" step of doc_links_md_member_missing_incremental removed one of two Python `area` methods and expected the closure-repair route. Since the Python namespace admission on main (merged into this branch with origin/main), a Python file whose surface changes always takes the full route (closure_decline reason=python_namespace_changed), so the step ran FORCED_FULL on every platform; the Windows leg was simply the first to report it. Nothing here depends on timing: the planner compares content hashes. The group now lives in a Ruby file. Ruby has no doc-link scope, so the lost method reports no removed name and the document re-resolves only through the ambiguous `path::member` rule, which this step exists to bind. (A Rust group was tried too: its scope reports the method as a removed name, so the step passed with the rule removed.) Test: the step takes closure repair with closure=2 (shapes.rb and docs/areas.md). With "ambiguous" dropped from doc_row_member_reason it stays on closure repair with closure=1 and keeps the stale ambiguous row where the full index has the Areas -> Square.area edge. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
|
Hi @bline, thank you again for this PR and for your patience while we worked on it. Your fix for missing members and its tests were the right foundation; everything below builds on them. We pushed one more small commit (62965bc) on top of your branch. It changes only a test:
No production code changed in this commit. Please pull before pushing again, since the branch has new commits on top. Thanks again for the contribution! |
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
|
Thank you for your patience, @bline. CI went green on this branch, but this evening's merges on main touched files this pull request also changes, so that green no longer covered today's main. We merged current main into the branch once more (one merge commit, 9fe25c4; your changes are untouched) and will merge once the fresh checks are green. Please pull before pushing again. |
|
Merged as 3be5a02 - thank you again, @bline! A |
What does this PR do?
Fixes #2587. A Markdown reference
path::memberwhose member the code filedoes not define became an exact
MENTIONSedge to the file. A renamed ordeleted definition therefore looked like a valid, coarser link, and nothing
recorded that the member was not found.
mdr_segmentnow reports how a member lookup ended, andmdr_resolve_pathuses that:
src/util/rounding.py::clamp(defined)clampsrc/shapes.py::Square::area(owner picks one)Square.areasrc/util/rounding.py::no_such_functionmissingsrc/shapes.py::area(twoareamethods, no owner)ambiguousdocs/other.md::Intro(a document's heading)This follows the C resolver:
cr_memberreports a missing member of anexisting type as
missingand never falls back to an edge on the type. Amissingrow is also what a missing path already gets, soindex_status'sunresolved counts now show member-level doc rot. Members written on non-code
files keep the file edge, because a document's headings are not graph
definitions. Line ranges without a member are unchanged.
The other suggestion in #2587, keeping the edge and recording the
unresolved member on it, would need an outcome that is both an edge and a row.
That is a new mechanism, so I went with the existing one. Happy to switch.
Evidence
doc_links_md_member_not_defined_issue2587intests/test_doc_links_md.cindexes the fixture in the table. Without the source change it fails on the
defect itself:
With it,
scripts/test.sh --suites doc_links_md,doc_links_rst,doc_links_adoc,doc_mentionsreports 96 passed, 0 failed.
Checklist
git commit -s) — required, CI rejectsunsigned commits (DCO, see CONTRIBUTING.md)
scripts/test.sh(the canonical leg), 9275 passed, 0 failed, 10 skipped,186 suites, Linux x86-64, gcc
scripts/lint.sh --ciintest-infrastructurelintcontainer(cppcheck + clang-format-20 + memory-core), "All linters passed"
Written with an AI agent (Claude); I reviewed the change and certify it via
the DCO sign-off.
🤖 Generated with Claude Code