Skip to content

fix(parser): stop folding trailing comments into Kotlin import targets - #824

Open
songguohfut wants to merge 1 commit into
tirth8205:mainfrom
songguohfut:fix/kotlin-import-trailing-comment
Open

fix(parser): stop folding trailing comments into Kotlin import targets#824
songguohfut wants to merge 1 commit into
tirth8205:mainfrom
songguohfut:fix/kotlin-import-trailing-comment

Conversation

@songguohfut

Copy link
Copy Markdown

Linked issue

No separate issue filed — the repro and root cause are self-contained below.

What & why

Kotlin files whose last import is followed by a long KDoc block fail to
parse entirely, with:

OSError: [Errno 63] File name too long: '<repo>/<dir>/import javax/inject/Inject\n\n/**\n * ...

Note the "path" in that error is actually a whole source comment.

Root cause

Three layers:

  1. tree-sitter-kotlin folds any comment that follows the last import into
    that import_header node. Minimal case — the node text for import b.C
    below is 'import b.C\n\n/** hi */':

    package a
    import b.C
    
    /** hi */
    class D
  2. _extract_import has branches for python, javascript, go, rust, c/cpp,
    java/csharp, solidity, scala, r, ruby, dart, verilog and julia — but not for
    Kotlin. Kotlin therefore falls through to the generic fallback:

    else:
        # Fallback: just record the text
        imports.append(text)

    so the module name becomes the import statement plus the trailing comment.

  3. _do_resolve_module joins that string into a filesystem path and calls
    target.is_file()os.stat. When the trailing comment is long enough the
    path exceeds the OS limit and raises OSError. _extract_imports has no
    try/except, so the exception propagates and the whole file is dropped.

Blast radius is wider than the crash

Every Kotlin file was affected — the last import always produced an
IMPORTS_FROM edge whose target carried the trailing comment. Only files whose
comment was long enough to overflow the path limit actually raised; the rest
silently emitted an unresolvable edge. In one 398-file Kotlin repo exactly one
file crashed, but every file with a trailing comment had a polluted edge.

Fix

Add a Kotlin branch to _extract_import that reads the identifier child
rather than the node text. Comments are separate multiline_comment siblings,
so this is immune to the folding. wildcard_import siblings get .*
re-appended, and import_alias is ignored so the original module is recorded.

The node structure this relies on:

Source children of import_header
import b.C import, identifier('b.C')
import b.C + trailing comment import, identifier('b.C'), multiline_comment
import b.C as E import, identifier('b.C'), import_alias('as E')
import b.* import, identifier('b'), ., wildcard_import('*')

14 lines, no behavior change for any other language.

How it was tested

New tests/test_kotlin_imports.py (8 cases: plain, trailing block comment,
trailing line comment, multi-import, alias, wildcard, wildcard + comment, and
the long-KDoc crash). All 8 fail on main and pass with this change — the
long-KDoc case reproduces the original OSError exactly.

$ uv run pytest tests/test_kotlin_imports.py --tb=line -q   # before the fix
8 failed in 0.17s

$ uv run pytest tests/test_kotlin_imports.py --tb=short -q  # after
8 passed in 0.12s

$ uv run pytest tests/ --tb=short -q
2406 passed, 5 skipped, 2 xpassed, 1 warning in 35.91s

$ uv run ruff check code_review_graph/
All checks passed!

$ uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional
Success: no issues found in 70 source files

Checklist

  • Tests added for new functionality
  • All tests pass: uv run pytest tests/ --tb=short -q
  • Linting passes: uv run ruff check code_review_graph/
  • Type checking passes: uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional
  • Lines are at most 100 characters
  • Docs updated where behavior changed — no user-facing docs cover per-language import extraction; the rationale is captured in the new branch's comment and the test module docstring.

tree-sitter-kotlin folds any comment that follows the LAST import into that
import_header node. `_extract_import` had no Kotlin branch, so it fell through
to the generic `imports.append(text)` fallback and recorded the entire node
text — import statement plus the trailing comment — as the module name.

`_do_resolve_module` then turned that string into a filesystem path and called
`os.stat` on it. A trailing KDoc block long enough to exceed the path limit
raised `OSError: [Errno 63] File name too long`, which `_extract_imports` does
not catch, so the whole file failed to parse.

Every Kotlin file was affected: the last import always produced an
IMPORTS_FROM edge whose target carried the trailing comment. Only files whose
trailing comment was long enough to overflow the path limit actually crashed.

Add a Kotlin branch that reads the `identifier` child (comments are separate
`multiline_comment` siblings) and re-appends ".*" for wildcard imports.

Co-Authored-By: Claude Opus 5 (1M context) <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

None yet

Development

Successfully merging this pull request may close these issues.

1 participant