#3603 resolves cross-file alias/import/require/use targets onto the real
defmodule node. Two guards ported from the competing #3566 so the resolver
does not over-reach:
- Only top-level modules are indexed as resolution targets. extract_elixir
marks them with _elixir_module; a nested defmodule (labeled with its bare
inner name) is left unmarked so an unrelated `use <Name>` from another file
cannot latch onto it. The marker rides through incremental rebuilds via the
resolution-context allow-list in watch.py and cli.py, so the fix does not
decay on the `graphify update` / watch path.
- A same-file alias is left unresolved: the import edge's source is the file
node, which already `contains` that module, so retargeting would duplicate
the pair as a weaker `imports` and clobber `contains` in the non-multi graph.
Adds regression tests for both guards plus an incremental-rebuild test that
routes through the real watch._rebuild_code builder (the path #3566's own
test bypassed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A module with no matching definition anywhere in the corpus, stdlib
or a hex dependency, must stay an external reference rather than
getting fabricated.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit da5e23a921)
Two different files each declaring a module with the same bare name
must leave the reference exactly as extracted rather than guessing
which one the caller meant.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 690d387626)
A module importing something declared in the same file already
resolved before this fix, since both ids share the same stem, and
must keep working exactly as before.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 8320da005a)
A module aliased from a different file now resolves to that module's
real, non dangling node.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 53877c6874)