Skip to content

fix(writer): propagate is_dependency so find_dead_code works for all languages - #1609

Merged
Shashankss1205 merged 1 commit into
mainfrom
fix/1595-function-is-dependency
Aug 13, 2026
Merged

fix(writer): propagate is_dependency so find_dead_code works for all languages#1609
Shashankss1205 merged 1 commit into
mainfrom
fix/1595-function-is-dependency

Conversation

@Shashankss1205

Copy link
Copy Markdown
Collaborator

Fixes the 7th report in #1595 (credit @rrodriguesNutrium). This is a total feature outage for roughly half the supported languages.

The bug

find_dead_code opens with (code_finder.py:857):

MATCH (func:Function)
WHERE func.is_dependency = false ...

but the writer never sets that property on contained items. add_file_to_graph builds each row as row = dict(item) and adds only path and cyclomatic_complexityis_dependency is read from file_data for the File node and never propagated down.

In Cypher null = false evaluates to null, not false, so every affected Function row is discarded and the tool returns an empty list.

It's language-dependent

The original report suggested this affects everything. It's narrower and that's why it hid so well: about half the extractors emit is_dependency per item and half don't. python.py does, so Python works; kotlin.py doesn't, so Kotlin silently returns nothing.

Reproduced on a 4-function Kotlin project, both backends:

before:  MATCH (f:Function) RETURN f.is_dependency  ->  null, null, null, null
         cgc analyze dead-code                      ->  "✓ No dead code found!"

after:   MATCH (f:Function) RETURN f.is_dependency  ->  false, false, false, false
         cgc analyze dead-code                      ->  2 functions (GreetingPreview, orphanNeverCalled)

Same Python project as a control returned 25 functions both before and after — unaffected, as expected.

The fix

One line in the item loop:

if label != "Module":
    row.setdefault("is_dependency", is_dependency)

setdefault rather than assignment so extractors that compute this per item keep their own answer — which also correctly marks functions inside dependency files. Module is excluded because it is the one label in item_mappings with no is_dependency column in the schema.

I chose the writer over making the query null-tolerant (coalesce(...)) because the property is genuinely expected to be present — code_finder.py reads caller.is_dependency a few lines later, and the asymmetry between the two sides is itself the hint.

Combined effect with #1596

The chain the reporter was actually after now works end to end:

find_dead_code()                                      -> ['GreetingPreview', 'orphanNeverCalled']
find_dead_code(exclude_decorated_with=['Preview'])    -> ['orphanNeverCalled']
find_dead_code(exclude_decorated_with=['Composable']) -> ['orphanNeverCalled']

Tests

Three regression tests driving the real GraphWriter path with item dicts that omit is_dependency — the reporter correctly identified that existing tests hand-build file_data with the property, which is exactly why the suite never caught this. Verified they fail on main and pass with the fix.

tests/unit/         1181 passed, 7 skipped
tests/integration/    44 passed

Stacked on #1599 (the CI fix); the integration numbers above include it.

find_dead_code filters on `func.is_dependency = false`. Roughly half the
language extractors never emit the property per item, and in Cypher
`null = false` is null rather than false -- so every function from those
extractors was silently discarded and the tool returned an empty list.

Reproduced on a 4-function Kotlin project (both backends): every Function
node had is_dependency = null and `cgc analyze dead-code` reported
"No dead code found" despite an obviously-uncalled function. Python was
unaffected because python.py emits the property itself.

setdefault is used so extractors that compute it per item keep their value.
Module is excluded -- it is the one label in item_mappings with no
is_dependency column in the schema.

Fixes the 7th report in #1595.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
code-graph-context-pack Ready Ready Preview Aug 13, 2026 6:36pm

@github-actions

Copy link
Copy Markdown
Contributor

Hi! 👋 Join our CodeGraphContext Discord channel to collaborate: https://discord.gg/dR4QY32uYQ

@github-actions

Copy link
Copy Markdown
Contributor

🔍 PR Code Graph Analysis

fix(writer): propagate is_dependency so find_dead_code works for all languages (#1609)

📊 Interactive Visualization

View the blast radius graph: PR Reviewer Dashboard

📦 Artifacts

The graph JSON has been uploaded as a build artifact: pr-code-graph-1609


Generated by CodeGraphContext using FalkorDB Lite

@Shashankss1205
Shashankss1205 merged commit 8d32941 into main Aug 13, 2026
17 of 20 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog tasks to Done in CGC Progress Board Aug 13, 2026
rrodriguesNutrium added a commit to rrodriguesNutrium/CodeGraphContext that referenced this pull request Aug 13, 2026
CodeGraphContext#1609 fixed the is_dependency propagation and added a writer-level test.
This adds the complementary end-to-end case: parse real source with a
real parser, write via GraphWriter.add_file_to_graph, then call
CodeFinder.find_dead_code and assert a genuinely uncalled function is
reported.

It builds no file_data by hand, which is the point. Hand-built fixtures
naturally include is_dependency, so every existing test passed while the
shipped path returned nothing for every project.

The language choice is load-bearing: python.py's _find_functions
hardcodes is_dependency per function, so a Python fixture would pass with
or without the fix. Kotlin does not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rrodriguesNutrium added a commit to rrodriguesNutrium/CodeGraphContext that referenced this pull request Aug 13, 2026
Kotlin had no golden despite sample_project_kotlin existing in fixtures,
so nothing asserted on the Kotlin graph's contents.

The goldens are the only tests in the repo that check real graph output
end to end. Everything else asserts on the parser's return dict built
from hand-written fixtures -- which is how the is_dependency bug fixed
in CodeGraphContext#1609 stayed invisible while the suite was green.

Baseline captures 216 nodes / 278 edges, with is_dependency=False on all
50 Function nodes and decorators populated on 5.

The absolute repo root inside each `uid` is normalised to <REPO_ROOT> so
the fixture carries no developer's home directory. `uid` is listed in the
test's VOLATILE_NODE_KEYS and is never compared, so this does not affect
the assertion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Shashankss1205 pushed a commit that referenced this pull request Aug 13, 2026
…in (#1598)

#1609 fixed the is_dependency propagation and added a writer-level test.
This adds the complementary end-to-end case: parse real source with a
real parser, write via GraphWriter.add_file_to_graph, then call
CodeFinder.find_dead_code and assert a genuinely uncalled function is
reported.

It builds no file_data by hand, which is the point. Hand-built fixtures
naturally include is_dependency, so every existing test passed while the
shipped path returned nothing for every project.

The language choice is load-bearing: python.py's _find_functions
hardcodes is_dependency per function, so a Python fixture would pass with
or without the fix. Kotlin does not.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Shashankss1205 pushed a commit that referenced this pull request Aug 13, 2026
…1618)

Kotlin had no golden despite sample_project_kotlin existing in fixtures,
so nothing asserted on the Kotlin graph's contents.

The goldens are the only tests in the repo that check real graph output
end to end. Everything else asserts on the parser's return dict built
from hand-written fixtures -- which is how the is_dependency bug fixed
in #1609 stayed invisible while the suite was green.

Baseline captures 216 nodes / 278 edges, with is_dependency=False on all
50 Function nodes and decorators populated on 5.

The absolute repo root inside each `uid` is normalised to <REPO_ROOT> so
the fixture carries no developer's home directory. `uid` is listed in the
test's VOLATILE_NODE_KEYS and is never compared, so this does not affect
the assertion.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant