fix(julia): emit imports for qualified, relative, and scoped-selected forms
Only bare-identifier imports (`using Foo`) emitted edges. tree-sitter-julia wraps qualified paths in `scoped_identifier` (`using Base.Threads`), relative paths in `import_path` (`using ..Sibling`), and the package of a `selected_import` may itself be a `scoped_identifier` (`import Base.Threads: nthreads`). None of those were matched, so qualified and relative imports were silently dropped, and scoped selected-imports pointed at the selected symbol instead of the module. Resolve the module name from identifier / scoped_identifier / import_path in all three positions. Adds fixture lines + a regression test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
safishamsi
co-authored by
Claude Opus 4.8
parent
7e24c3b7e4
commit
984a6a8f0a
+31
-11
@@ -7285,19 +7285,39 @@ def extract_julia(path: Path) -> dict:
|
||||
# Using / Import
|
||||
if t in ("using_statement", "import_statement"):
|
||||
line = node.start_point[0] + 1
|
||||
|
||||
def _julia_mod_name(n):
|
||||
# identifier (`Foo`), scoped_identifier (`Base.Threads`), or
|
||||
# import_path (relative `..Sibling`) -> the module name. Only bare
|
||||
# identifiers were handled, so qualified/relative imports — and the
|
||||
# scoped package of a `selected_import` — were silently dropped.
|
||||
if n.type == "import_path":
|
||||
ids = [c for c in n.children if c.type == "identifier"]
|
||||
return _read_text(ids[-1], source) if ids else None
|
||||
if n.type in ("identifier", "scoped_identifier"):
|
||||
return _read_text(n, source)
|
||||
return None
|
||||
|
||||
def _emit_import(name):
|
||||
if not name:
|
||||
return
|
||||
imp_nid = _make_id(name)
|
||||
add_node(imp_nid, name, line)
|
||||
add_edge(scope_nid, imp_nid, "imports", line, context="import")
|
||||
|
||||
for child in node.children:
|
||||
if child.type == "identifier":
|
||||
mod_name = _read_text(child, source)
|
||||
imp_nid = _make_id(mod_name)
|
||||
add_node(imp_nid, mod_name, line)
|
||||
add_edge(scope_nid, imp_nid, "imports", line, context="import")
|
||||
if child.type in ("identifier", "scoped_identifier", "import_path"):
|
||||
_emit_import(_julia_mod_name(child))
|
||||
elif child.type == "selected_import":
|
||||
identifiers = [c for c in child.children if c.type == "identifier"]
|
||||
if identifiers:
|
||||
pkg_name = _read_text(identifiers[0], source)
|
||||
pkg_nid = _make_id(pkg_name)
|
||||
add_node(pkg_nid, pkg_name, line)
|
||||
add_edge(scope_nid, pkg_nid, "imports", line, context="import")
|
||||
# `import Base.Threads: nthreads` — the package (first named
|
||||
# child) may itself be a scoped_identifier/import_path.
|
||||
pkg = next(
|
||||
(c for c in child.children
|
||||
if c.type in ("identifier", "scoped_identifier", "import_path")),
|
||||
None,
|
||||
)
|
||||
if pkg is not None:
|
||||
_emit_import(_julia_mod_name(pkg))
|
||||
return
|
||||
|
||||
for child in node.children:
|
||||
|
||||
Vendored
+2
@@ -2,6 +2,8 @@ module Geometry
|
||||
|
||||
using LinearAlgebra
|
||||
import Base: show
|
||||
using Base.Threads
|
||||
using ..ParentModule
|
||||
|
||||
abstract type Shape end
|
||||
|
||||
|
||||
@@ -1446,6 +1446,20 @@ def test_julia_import_edges_have_import_context():
|
||||
assert all(e.get("context") == "import" for e in import_edges)
|
||||
|
||||
|
||||
def test_julia_qualified_and_relative_imports():
|
||||
"""Qualified (`using Base.Threads`) and relative (`using ..Mod`) imports
|
||||
must emit edges.
|
||||
|
||||
The handler only matched bare identifiers, so scoped_identifier and
|
||||
import_path forms — and the scoped package of a selected_import — were
|
||||
silently dropped.
|
||||
"""
|
||||
r = extract_julia(FIXTURES / "sample.jl")
|
||||
targets = [e["target"] for e in r["edges"] if e["relation"] == "imports"]
|
||||
assert any("base_threads" in t for t in targets), "qualified import Base.Threads missing"
|
||||
assert any("parentmodule" in t for t in targets), "relative import ParentModule missing"
|
||||
|
||||
|
||||
def test_julia_finds_inherits():
|
||||
r = extract_julia(FIXTURES / "sample.jl")
|
||||
inherits = [e for e in r["edges"] if e["relation"] == "inherits"]
|
||||
|
||||
Reference in New Issue
Block a user