Commit Graph
1544 Commits
Author SHA1 Message Date
Eric MinishandClaude Opus 5.5 23ff26be68 fix(python): an aliased module import inside a function links its calls (#2607)
`import a.b as X` written inside a function binds X there, ahead of any
module-level binding of X, so X.f() reaches a/b.py's f, as the same
import at module level already did. An undotted alias is left alone,
since an optional dependency's name can match any project file.
mealie's lifespan_fn now links init_db.main; the other repos are
unchanged.

Fixes issue 2600.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:04:29 +00:00
Eric MinishandClaude Opus 5.5 4f222a3d65 fix(python): the module of a from-import no longer links a same-named variable (#2603)
The module of a Python `from X import ...` names a module or package,
never a symbol, so `from app import email` no longer links the
importing file to a project variable named app, like a FastAPI or
Flask app = FastAPI(). A from-import module that resolves to anything
but a file or module links nothing. On five Python repos this removes
12 wrong import links and nothing else.

Fixes issue 2584.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:02:50 +00:00
Eric MinishandClaude Opus 5.5 e48565067e fix(python): a call through a module-level instance links its class's method (#2608)
A Python call through a module-level instance of the same file, like
_svc.delete(obj) after _svc = SceneService(), now links to the method
its class has or inherits, as a method value through that global
already did.

On django and fastapi: 50 correct links added, 42 moved to the right
class (DEBUG_ENGINE's Engine, the dispatch tests' Signal), confidence
raised on about 400 more. CPU time on django is unchanged.

Fixes issue 2582.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:01:54 +00:00
Eric MinishandClaude Opus 5.5 cc1eb1f942 fix(python): a call on an imported outside module no longer links a same-named project method (#2606)
A Python call on a module the file imports from outside the project,
like subprocess.run(...) after import subprocess or sp.run(...) after
import subprocess as sp, is that module's function, never a project
class's method of the same name. The receiver must be bound only by
such imports: an assignment, loop or tuple target, a global write in a
function, or a fallback class or def of the name keeps the old lookup.

On django, mealie, fastapi and flask this removes 168 wrong links
(mock.call, time.sleep, sa.text, unicodedata.normalize, click.command)
and adds none. CPU time on django is unchanged.

Fixes issue 2599.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:00:22 +00:00
Eric MinishandClaude Opus 5.5 c8f154b9f4 fix(explore): pin the dominant-file aggregation to an edges-first plan (#2575)
The dominant-file aggregation behind codegraph_explore could let SQLite
drive the query from the nodes table, which on a large index took
seconds to a minute. The query now pins an edges-first plan. On four
indexes it returns the same rows, 4 to 12 times faster.

Fixes issue 2571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:59:07 +00:00
Colby MchenryandClaude Opus 5.5 b5553e238a fix(rust): an impl's associated type or const no longer takes a bare name or a module path (#2707)
A `type` or `const` written inside an `impl` belongs to the type: Rust
reaches it only through a path like `Self::Err`, `<T as FromStr>::Err` or
`T::Err`, never by its name alone, and no module path or `use` names it.
Both extractors put it at file scope under its bare name, so the resolver
could not tell it from a module's own alias:
- a same-file `Err(…)` call linked to a `FromStr` impl's `type Err`, and
  serde's `Ok(…)` calls to a serializer's `type Ok`;
- axum's routing tests' `Response` linked to the `type Response` of
  `routing/mod.rs`'s `impl Service`, a private item the modules inside
  it can see;
- `io::Error` and `std::error::Error` linked to the `type Error` of an
  impl in the same file, and serde's `use crate::de::Error` to one in
  `de/mod.rs`.

Fix:
- Both extractors (rustImplItemOwner, and the kernel's impl_item_owner)
  qualify an item written directly in an impl by the impl's type, as they
  already qualify its methods: `ValueHint::Err`, `Limits::MAX`. A type no
  single name stands for keeps the impl's spelling, whitespace collapsed:
  `(A, B)::First`, `[u8]::Out`, `u64::WIDTH`.
- isRustAssociatedItem: a Rust type alias or const with a qualified name.
  Nothing else of those kinds gets one: an inline module adds no prefix,
  a function body's items aren't indexed, and a trait's default `type`
  is already its trait's.
- isRustNameInScope: such an item never matches a bare name, and matches a
  path only as `Self::X` in its own impl or as `<…>::X` (unchanged).
- resolveRustPathReference never picks one for a `crate::m::X` path.

Tests: rust-associated-item-scope.test.ts, 6 tests, on both engines; 5
fail on origin/main. The kernel parity torture fixture gains associated
items on a tuple, a slice reference and a primitive.

A/B on fresh indexes, origin/main 5530676f vs this change. Every changed
edge was triaged; no right link was lost:
- axum: 8 wrong links gone, 14 moved to axum-core's `pub type Response`.
- tokio: 46 wrong links gone.
- clap: 12 wrong links gone, 7 of them `Err(…)` calls.
- serde: 98 wrong links gone; `First<…>`/`Second<…>` now reach the
  module's aliases.
- ripgrep: 54 wrong links gone; `impl Captures for RegexCaptures` (3)
  now implements grep-matcher's `Captures` trait.
- gleam: 5 wrong links gone, 10 moved to the right target, 1 moved from
  one wrong target to another.
- dioxus: 71 wrong links gone, 40 moved to the right target, 3 moved from
  one wrong target to another.
- Controls (gin, serilog, flask, express) byte-identical; indexing time
  unchanged within noise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:57:03 +00:00
Colby MchenryandClaude Opus 5.5 6c49bfa667 fix(go): a call through a variable declared with another package's type reaches that type's method (#2706)
Go receiver inference read a parameter's type only when the line
patterns could: a lowercase name of the caller's own package (`s
*server`) or a capitalized one (`lg Logger`). A parameter declared
through a package, like `client rest.Interface`, `c clock.PassiveClock`
or `t *testing.T`, had no type, so a call on it was matched by name:
kubernetes' `client.Patch()` reached `RESTClient::Patch` instead of the
interface, `c.Now()` an unrelated `Clock`, and every `t.Errorf(…)` a
test helper's `T` interface. Only standard method names (PR 2664) and
receivers named like an import (PR 2448) asked the scope reader.

inferLocalReceiverType now asks the scope reader first for every Go
receiver. The declaration in scope (a parameter, a result, a name
grouped with others, a `var (…)` spec, a function literal's parameter)
gives the named type it writes, as GoReceiverDecl.declared, ahead of
the patterns, which scan back with no block scope. matchMethodCall,
matchMemberFunctionRef and matchGoFieldChainCall all use it:
- a project type resolves in its own package, through embedding and
  aliases;
- a type from outside the project, a predeclared one or an alias of
  either (goHasNoProjectMethods) reaches none of the project's methods,
  and neither does a type literal;
- a qualifier none of the file's imports names keeps the old lookup by
  name.
Standard method names keep the rules PR 2664 gave them. Any other name
the declared project type lacks goes on to the name strategies, as on a
receiver of unread type. The block that typed only receivers named
like an import is subsumed and removed, with the field it read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:38:24 +00:00
Colby MchenryandClaude Opus 5.5 70783f31f1 fix(objc): a message to an ivar or a property reaches the class it is declared as (#2703)
An Objective-C message to a local or a parameter was typed by its
declaration (`FMResultSet *rs` makes `[rs close]` FMResultSet's). One to
an instance variable or a property was not, since that declaration sits
outside the calling method: in a header's @interface, an @implementation's
ivar block, a superclass, or synthesized for a property. The receiver's
name decided instead. ObjFW's tar tool's `[_archive nextEntry]` reached
OFLHAArchive::nextEntry, and React Native's `[_displayLink invalidate]` on
a CADisplayLink reached RN's own RCTDisplayLink::invalidate.

- objcFileMembers reads what each class declares, per file: the ivar
  block right after an @interface head (seen by subclasses; the head may
  go on over several lines, a protocol list on a line of its own), a
  class extension's or an @implementation's ivar block (the class's own),
  @property declarations, including ObjFW's two-line ones and IBOutlet
  ones, and @synthesize lines. Types take protocol lists, type arguments
  and ObjFW's OF_GENERIC(...).
- objcMemberReceiverType, after the local inferrer, follows the language.
  `self.name` is a property of the class or a superclass. A bare name is
  an ivar: the class's own, one its own property synthesizes (`_name`,
  never a category property's), one @synthesize names, or a superclass's
  @interface ivar. A bare name is never a property's: `arcs` in
  `initWithArcs: (...)arcs` is the parameter. A capitalized bare name is a
  class, and `self.name` needs a property node, which skips most lookups.
  The type then takes the typed path (resolveMethodOnType at 0.9), and a
  class from outside the project has no project method, as for locals.
- objcClassFiles: when more than one file declares `@interface Name`
  itself, those are namesakes in separate targets, and only the ones in
  the calling file's directory count. SDWebImage's TV demo ViewController
  was otherwise typed by the macOS demo's `NSImageView *imageView1`.
- localReceiverTypePatterns('objc'): a local's or a parameter's type may
  carry OF_GENERIC(...), like `OFMutableArray OF_GENERIC(OFNumber *) *arcs`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:35:36 +00:00
Colby MchenryandClaude Opus 5.5 f2f5dee044 fix(rust): a call through a Pin, Rc or Box self reaches the method Rust picks, inherent first (#2701)
A Rust method called through a self declared Pin<&mut Self>, Box<Self>,
Rc<Self> or Arc<Self> was typed by its wrapper. tokio's
self.poll_flush(cx) in impl AsyncWrite for File went to its blanket impl
AsyncWrite for Pin<P>, whose poll_flush would need a Pin<&mut Pin<...>>,
and nearly every other such call linked to nothing: tokio's
self.poll_write_priv(..) and self.get_pin_mut(), dioxus's
self.in_scope(..) through self: &Rc<Self>.

Such a call is now looked up as Rust does: the type's own method taking
self through that wrapper first, then the wrapper's own (Pin::get_mut,
Rc's clone: std's, which the index doesn't hold, or a project impl on the
wrapper taking &self), then the type's other methods by deref. A value
declared Pin<&mut T> is looked up the same way on T, so
read.poll_read(..) on a generic R no longer reaches the Pin<P> impl.

A type's inherent method comes before a trait's of the same name, as in
Rust: on a path (tokio's Arc::from_raw(ptr) is std's, not its impl Link
for Arc<ScheduledIo>'s), on a typed value, and through self, where each
of several trait impls for one type calls its own block's method. In a
trait impl, fn wake(self) { self.wake() } hands the call on to the
type's own method, never back to itself, and (self.f)(x) calls what a
field holds, no method. A method called on a tuple, serde's
(self.ip(), self.port()).serialize(s), is no named type's.

A/B on tokio, axum, clap, serde, ripgrep, gleam and dioxus: 30 wrong
links removed, 13 moved to the right target, 74 right links added, none
lost. express, gin, flask and leveldb are byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:32:16 +00:00
Eric MinishandClaude Opus 5.5 8beab37c46 fix(resolution): a call that is a braceless if/while/for/do body is a bare call (#2592)
A receiver-less JS/TS call written as the body of a braceless if, while,
for or do, like `if (e.key === "Escape") setOpen(false);`, is now read
as a bare call. In the JS family a receiver ends in `.` or `?.`, so a
`)` right before a call's name can only close a statement header; `do`
joins the bare-call keywords. Go keeps its old reading. Before, such a
call skipped the bare-call guards and could link to another file's
same-named member, like a context interface's `setOpen` property.

Fixes issue 2585.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 05:08:42 +00:00
Eric MinishandClaude Opus 5.5 18248d191e docs(agents): describe the instructions-file block the installer writes again (#1962)
AGENTS.md said the installer no longer writes an instructions-file block,
but since PR #704 the Claude, Codex, Gemini and opencode targets write a
short one again, while Cursor and Kiro only strip an old one. The
architecture notes and house rules now describe that block and keep tool
guidance in server-instructions.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:23:19 +00:00
Eric MinishandClaude Opus 5.5 fc470886ac fix(agent-eval): accept the trust dialog on "Yes", never type into a bare shell (#1925)
Current Claude Code builds list the per-folder trust dialog's options in
a different order, so itrun.sh now moves onto "Yes, I trust this folder"
before pressing Enter, whichever order the build uses, and stops instead
of typing the prompt into a bare shell when claude has already exited.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:22:24 +00:00
Colby MchenryandClaude Opus 5.5 5530676f41 fix(rust): a Self:: call is the function of the type whose impl it is in (#2700)
A Rust Self::x(...) call reached the resolver as a method call on a
receiver named Self, which names no type. So it fell to a guess by the
name alone, and linked only when nothing else in the project shared
that name. clap's Self::new(...) calls in impl Error, ValueParser and
the like stayed unresolved, and so did tokio's, axum's and serde's.
dioxus's Self::current() stopped resolving once its Android tooling's
AndroidTools::current was indexed.

Self is now the type of the impl (or trait) the call is written in. The
call reaches that type's function, or its variant for Self::Text(...),
in the type's own file first, then the nearest. As in Rust, the type's
inherent function comes first, with cfg twins standing for one another.
A trait impl's function is taken only when it is the only one, and
several trait impls of one name (From<A>, From<B>) are left unresolved.
Inside a trait impl, a call to the function's own name hands on to the
type's own function, so it never links to itself there. In the type's
own impl such a call is a recursion and stays one. A trait's own method
is the fallback only where nothing could shadow it.

A type from outside the project, such as axum's impl Listener for
tokio::net::TcpListener, has only the impls written beside the call.
When the type has no such function, the call stays unresolved instead
of going to another type's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 02:08:18 +00:00
Colby MchenryandClaude Opus 5.5 204315274e fix(cpp): every name a declaration lists has its type, like strings_found in ByteBuffer symbols_found, strings_found; (#2698)
C++ receiver inference read a declaration with a regex that wants the type
right before the name. A declaration that lists several names writes the type
once, before the first, so the later names were never read: google/breakpad's
`strings_found.Size()` after `ByteBuffer symbols_found, strings_found;`
linked nothing, and a later name could take the type of an earlier variable
of the same name further up.

matchCppListedDeclarator reads such a declaration from its start (specifiers,
the type with its template arguments paired, then each declarator with its
own pointer and reference marks, qualifiers, annotations, array bounds and
initializer) and gives a later name the declaration's type plus its own `*`s
and `&`s: `Foo *a, b;` declares one pointer. Names are told apart only by
commas at the statement's own depth, so template arguments, a call's or a
constructor's arguments, an initializer list or an expression list no name.
It runs only where the declarator regex finds nothing on a line, in all three
declaration readers: the receiver scan (and its header scan), a class's data
members (`Table *index_, *data_;`), and the check that a bare call names a
local.

A/B on main 036832d3 with current upstream clones: breakpad +30 added,
5 overload retargets wrong to right, 66 guesses now typed; protobuf +97,
1 retarget wrong to right, 9 removed (5 wrong, 4 single-candidate guesses on
message classes the C++ index lacks, now like the first name in their list);
rocksdb +43, 5 wrong removed; leveldb +4. glog and redis byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:52:07 +00:00
Colby MchenryandClaude Opus 5.5 ed8957710f fix(objc): a file-scope constant or global is indexed, in an @implementation too (#2699)
Objective-C read a file-scope declaration through the generic variable
fallback, which takes only a declarator that is a bare name (`int count;`).
Its most common globals were never indexed: `NSString *const
SDWebImageErrorDomain = @"…";`, `static const NSInteger kMaxRetries = 3;`,
`static dispatch_queue_t queues[4];`. A declaration written inside an
@implementation, file-scope C in the language, was not read at all,
because the class counts as an enclosing scope.

- tree-sitter.ts: Objective-C takes C's declarator branch in
  extractVariable (initialized, pointer and array declarators, with the
  initializer as the signature), keeping the bare names it always read.
  A declaration whose parent is an implementation_definition takes the
  variable branch; its globals are qualified under the class, as the
  C functions written there already are. A block or function-pointer
  variable reads as a prototype, as in C, and stays out.
- c-cpp.ts: isConstDeclaration, C's isConst, is shared, and objc.ts uses
  it, so `static const NSInteger kMaxRetries` is a constant.
- name-matcher.ts: a global that a .m or .mm file defines joins the C
  types that #2690 made file-local (OBJC_FILE_LOCAL_KINDS). A new
  isObjcFileLocalElsewhere drops such a candidate in the exact-match and
  fuzzy chains, before one is picked, and isVisibleAcrossFiles applies it
  to the pick. Before the pick, so that a header's `extern NSString
  *MJConfigFile;` stands for the definition in variables.m. Rejecting only
  the pick left Hammerspoon's MJConfigFile references unresolved. Without
  the rule, React Native's completionHandler(nil, image) block-parameter
  calls reached a completionHandler in another .mm, and #include <vector>
  a .mm's vector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:43:14 +00:00
Colby MchenryandClaude Opus 5.5 60b2f1e7bb fix(rust): a call reaches a project impl on a std type only as Rust would pick it (#2697)
A crate can't declare a method on String, Vec, Arc or NonNull, only
implement a trait for one, and name matching took those impls for any
call of that name. Every String::from("...") in dioxus's CLI went to its
impl From<IDI> for String, tokio's NonNull::from(waiter) calls to its
impl From<&Handle> for NonNull<Entry>, its tests' files.iter() to an
internal Storage trait's impl for Vec, and clap's String::from calls
to its impl From<Str> for OsString.

A call into a method of a project impl on a std type now stands only
when Rust could pick it. A std trait (From, PartialEq, ...) is
implemented for the crate's own type argument, so the call must pass
one: built from it (IDI::Install), self in an impl of it, or a name
the enclosing function declares with it (fn from(name: Str)). A trait
of the project's must be in scope in the calling file: declared,
implemented or imported there, or brought in by a glob that may carry
it. Otherwise the call is left unresolved, since what it calls is the
standard library's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:37:17 +00:00
Colby MchenryandClaude Opus 5.5 3273f20f47 fix(objc): a doc comment inside an @implementation documents the method below it (#2696)
Inside an Objective-C @implementation, tree-sitter-objc wraps each
method, function and declaration in an implementation_definition of its
own, and the comment above it is the wrapper's sibling, not the method's.
getPrecedingDocstring looked only at the method's own siblings, so no
method, function or static written in an @implementation had its doc
comment, while the same comment above an @interface property was read.

- tree-sitter-helpers.ts: implementation_definition joins
  DOCSTRING_WRAPPER_TYPES. Each wraps exactly one item, so the climb
  cannot hand a comment to a neighbour: a comment above an @synthesize
  stays its own.
- codegraph-kernel docstring.rs: the faithful port's wrapper list gains
  it too. The kernel does not walk Objective-C, so the entry only keeps
  the two lists alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:16:23 +00:00
Colby MchenryandClaude Opus 5.5 036832d3a7 fix(extraction): a build folder inside src/ is indexed for its Rust files too (#2695)
A folder named build below src/ was indexed for its TypeScript, JSX,
Vue, Svelte, Astro, Go and C# files, but not Rust's. dioxus's CLI keeps
its whole build pipeline in packages/cli/src/build/, gleam's compiler
its project and package compilers in compiler-core/src/build/, and
tauri-plugin its build-script helpers in src/build/. Cargo writes its
output to target/, so .rs files in such a folder are hand-written, and
they are now indexed as well.

Rust waited on its name matching: indexing dioxus's src/build/patch.rs,
which declares a private type Result, moved 158 Result references off
the crate's own alias. A private item now stays in its own module, so
those references keep their target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:07:22 +00:00
Colby MchenryandClaude Opus 5.5 6f8e6caad9 fix(c,cpp): a source implements the header beside it that it reaches through other headers (#2693)
upb's reflection sources include only their internal header:
upb/reflection/field_def.c includes upb/reflection/internal/field_def.h,
which reaches the upb/reflection/field_def.h it implements through def.h.
So the translation-unit rule of PR 2684 never read field_def.c as that
header's implementation, and 343 calls from protobuf's Python extension,
plus 88 from its Lua binding, still went to the copy of upb that the PHP
extension bundles in php-upb.c.

When a source includes no header named like it in its own folder, one
there that it includes through other headers counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 01:00:25 +00:00
Colby MchenryandClaude Opus 5.5 1b12bf5b49 fix(objc,c,cpp): an enum declared with NS_ENUM, NS_OPTIONS or CF_ENUM is indexed (#2694)
Foundation's enum macros declare most enums in Objective-C and in the C
and C++ headers beside it: `typedef NS_ENUM(NSInteger, SDImageCacheType)
{ … };`. The parser reads the macro as a broken typedef, so the enum and
its values were never indexed (SDWebImage had no enum at all), and a junk
type alias named after the first value, or after `(NSInteger, Name)` in
C++, stood in their place.

- c-cpp.ts: rewriteFoundationEnumMacros rewrites the macro in place as
  `enum Name {`. The `typedef`, the rest of the macro's name, its
  parentheses and its first argument (the underlying type, or an
  NS_ERROR_ENUM's domain) become spaces, so every offset stays. It matches
  on the code with comments, literals and directives masked, so the
  macro's own `#define` is left alone. NS_ENUM, NS_OPTIONS,
  NS_CLOSED_ENUM, NS_ERROR_ENUM, CF_ENUM, CF_OPTIONS and CF_CLOSED_ENUM
  share the shape. The C and C++ preParse run it first.
- objc.ts: preParse runs it before the lone-macro blank.

The kernel takes C and C++ input from the hoisted preParse, so it needs no
change. On the five repos' 1,342 C/C++ files the kernel and wasm agree
byte for byte, and 17 more files now parse clean enough for the kernel to
take them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:59:54 +00:00
Colby MchenryandClaude Opus 5.5 65d734236e fix(rust): a private item, or one another crate holds, no longer takes a name a file imports (#2692)
A Rust type alias declared without pub recorded no visibility in either
engine, so name matching took dioxus's private type Result in
src/build/patch.rs for the Result<...> a file means through
use crate::Result. Type aliases now record it, as functions and structs
already do, and a private module item is out of scope outside its own
module ahead of the ranking. The pipeline's veto already rejected such
a pick after the ranking, which left the reference unresolved: that is
what kept tokio's timeout(...), split(...) and sleep(...) calls from
linking, since a private namesake outranked the function they import.

With the private items gone, a runner-up from an unrelated crate could
win instead: tokio's tests' spawn(...) calls, under
use tokio_test::task::spawn, went to the examples crate's pub fn spawn.
So a name a use binds is now an item of the crate its path starts from,
or of a project crate that one's [dependencies] name, in turn, which a
facade's re-exports need: clap::Command is clap_builder's. crate::,
self:: and super:: start from the file's own crate; a named root counts
when the file's own manifest lists it. Dependencies are found by path
(their own, or the workspace's for workspace = true), so renamed keys
and crates outside the members land, and dotted keys such as
helper.workspace = true are read. Dev and build dependencies are not
re-exported, so they don't count: tokio's own use crate::spawn, whose
spawn sits in a macro the index doesn't see, stays unresolved instead
of going to tokio-test's. A file in no crate the manifests name, or a
path from anything else, is matched as before.

reference-target-kind's sibling-crate fixture re-exported pupil_core
without depending on it, which Cargo rejects; it now declares it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:44:52 +00:00
Colby MchenryandClaude Opus 5.5 40987d7776 fix(objc): a macro alone on its line no longer hides the declaration below it (#2691)
A macro on a line of its own, like NS_ASSUME_NONNULL_BEGIN,
OF_SUBCLASSING_RESTRICTED or RCT_EXTERN_C_BEGIN, reads to tree-sitter-objc
as the start of a declaration and swallows what follows: an @interface
under it became a function named after its last protocol, and a typedef
under it a variable `typedef` plus a variable named after the type. C and
C++ already blank such a macro in preParse (blankLoneMacroLines);
Objective-C had no preParse.

- c-cpp.ts: blankLoneMacroLines takes the language's rules, and C and C++
  keep theirs unchanged. OBJC_LONE_MACROS lets the code below the macro
  start with `@` (@interface, @end). It reads a preprocessor line above the
  macro as ending at its own line: `#import <Foundation/Foundation.h>` ends
  in `>`, an operator to C's rule, which left NS_ASSUME_NONNULL_BEGIN in
  place while the OF_SUBCLASSING_RESTRICTED below it was blanked, a worse
  parse than either. And it leaves a macro that is a method's whole body
  (`{ OF_UNRECOGNIZED_SELECTOR }`): blanking it changed how the parser
  recovered from an earlier misread, and OFMutableString.m lost 11 calls.
- objc.ts: preParse blanks with those rules.
- name-matcher.ts: objcSupertypesOf reads the superclass from the
  @interface line within the class rather than the class's first line. A
  class now starts at an attribute macro written above its @interface, like
  NS_SWIFT_NAME(...), and KSCrash's [super validateSetupWithError:] had lost
  its superclass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:41:26 +00:00
Colby MchenryandClaude Opus 5.5 6c202bca32 fix(objc): a struct, union or enum defined in a variable declaration is indexed (#2690)
Objective-C kept the gap that PR #2446 closed for C and C++: a struct,
union or enum defined in the type of a file-scope declaration, like
`static struct { Class isa; } placeholder;`, `struct Foo { int a; } foo;`
or `enum { ModeA, ModeB } mode;`, never became a node. The walker's
declaration branch extracted the variable and skipped the declaration's
children, and Objective-C did not take the declared-type walk.

- tree-sitter.ts: Objective-C walks a type defined in a declaration's
  type, as C does, also when the tree has errors. Most Objective-C trees
  have errors (a lone macro like NS_ASSUME_NONNULL_BEGIN is enough; 832 of
  ObjFW's 1087 Objective-C files), so a clean-tree gate would skip nearly
  every real site, and neither grammar has a namespace or a class written
  as a type that error recovery could close at the wrong brace.
- objc.ts: resolveName composes selector naming with C's
  unnamedTypeVariableName, so an unnamed type takes the first variable its
  declaration declares (in function and method bodies too), and
  getDeclarationWrapper makes the declaration's comment the docstring.
- c-cpp.ts: export definingDeclaration and unnamedTypeVariableName.
- name-matcher.ts: a struct, union, enum or typedef that a .m or .mm file
  defines is visible only to that file, as isCppTranslationUnitLocal keeps
  a .c file's. Without it, ObjFW's calls of AmigaOS's Lock(path, mode)
  linked to the runtime's private struct Lock in synchronized.m. A class
  stays visible: it is the runtime's, wherever it is written.

The walk also recovers a typedef written right after a line holding only a
macro (OF_ASSUME_NONNULL_BEGIN, RCT_EXTERN_C_BEGIN), which the parser reads
as a declaration of a variable: ObjFW's public enums with their values,
and React Native's RCTMethodInfo, were missing. Objective-C has no kernel
walker, so the kernel is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:03:37 +00:00
Colby MchenryandClaude Opus 5.5 12ea27faf4 fix(swift): a local declared through try, await or a generic constructor has the type constructed (#2689)
The Swift declaration pattern behind receiver typing read `name = Type(`
only, so a local declared through `try`, `try!`, `try?` or `await`, or with
a generic type's constructor, had no type at all. Kingfisher's
`let storage = try! DiskStorage.Backend<String>(config: config)` left
`storage.store(…)` to name matching among every `store` in the project.

The pattern now reads type arguments, as the Java and C# patterns do, and
steps over `try`/`await` where the line declares the local (`let`/`var`)
and no member follows the constructor call there. A bare assignment through
`try` is left as before: swift-nio's `channel = try ServerBootstrap(…)` goes
on into `.bind(…).wait()` on the lines below, a value of another type, and
typing it by the chain's head hid the `var channel: Channel?` it was
declared as. Likewise realm-swift's `let obj = try! Realm().write { … }` is
a value of what `write` returns. resolveMethodOnType still checks the
method on the type, so a local typed wrongly links nothing.

swift-try-initialized-locals.test.ts gives every target a namesake declared
before it on another type, names no local after its type, and pins the
assignment and the chained-call cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:36:16 +00:00
Colby MchenryandClaude Opus 5.5 e8b478a00e fix(sync): record only indexed files as synthesis inputs (#2688)
A sync whose code lazy-loads a workspace package failed with "FOREIGN KEY
constraint failed" and rolled back, and every later sync did the same
(issue 2565). lazyValueModules names the module a lazy value loads as a
synthesis input, and for `import('icons')` or `import('@vben/layouts')`
the resolver gives the package directory, which is not an indexed file.
synthesis_inputs.file_path references files(path), so the stage's publish
step failed. A file that leaves the index while the passes run broke it
the same way.

Both places that write synthesis_inputs now keep only paths the files
table holds: replaceSynthesisInputs on the index, and SynthesisStage's
publish, inside its write transaction. The directory never matched a
changed file anyway, so nothing is lost.

A/B on main 3308cff0: fresh indexes of vben, excalidraw and zod are
byte-identical; vben's sync after editing its five layouts/index.ts files
exits 1 on main and 0 here, and the synced graph equals a fresh index of
the edited tree.

Reported by @bompus; @inth3shadows found the same cause.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:24:06 +00:00
Colby MchenryandClaude Opus 5.5 c65f9bb7eb fix(extraction): a build folder inside src/ is indexed for its Go and C# files too (#2687)
A folder named build below src/ was indexed only for its TypeScript, JSX,
Vue, Svelte and Astro files, so Go's own src/go/build package, a
module's src/build/version.go or a .NET solution's src/Build project
stayed out of the graph. Go and .NET toolchains never write source into
a build folder (their output is binaries, bin/ and obj/), so .go and .cs
files there are hand-written and now indexed as well.

Rust waits: its name matching doesn't yet keep a private item to its own
module, so indexing dioxus's src/build/patch.rs, which declares a private
type Result, moved 158 Result references off the crate's own alias. A
test pins .rs as still excluded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:21:54 +00:00
Colby MchenryandClaude Opus 5.5 3308cff071 fix(swift): a call through a prefix operator, try or await keeps its callee and receiver (#2686)
tree-sitter-swift binds a prefix operator to the leftmost operand:
`!isReady()` parses as `(!isReady)()`, and `!store.contains(id)` as
`(!store).contains(id)`. `try` and `await` before a chain bind to the part
before its last call: `try! Decoder().decode(d)` parses as
`(try! Decoder()).decode(d)`. Both engines read the callee or receiver node
as written, so the call was named `!isReady`, which never resolves, or it
lost its receiver and name-matched whichever `contains` or `decode` came
first; a type path behind a `!` lost its path too.

Both walkers now strip these wrappers (a prefix operator other than an
implicit member's `.`, `try` and `await`) off a call's callee and receiver.
They read a receiver chain's text from its innermost wrapped operand on, for
the chained-call encoding and the type-path receiver, and look through a
prefix operator for the type a member read references: `!Config.shared.isOn`
references `Config`. An operator applied to a parenthesized value, `!(x)` or
`-(a + b)`, parses as a call of the operator and now emits no call.

swift-wrapped-call-receivers.test.ts checks the edges, and
TortureWrappedCalls.swift pins both engines' refs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:31:31 +00:00
Colby MchenryandClaude Opus 5.5 951d575e62 fix(resolution): a barrel's export { A } from './x' links what ./x exports, not a namesake (#2685)
A barrel's own export { A, B as C } from './x' emits one imports
reference per name it passes on, named as ./x calls it. No import binds
a re-exported name, so the resolver looked each one up by its name alone
and could reach a namesake elsewhere in the project, or a project
function named like a package's export.

Each such name now resolves through the module the statement names, as
an import does, following barrels of barrels and renames. A name passed
on from an outside package counts as bound to that package, so it never
name-matches a project symbol. A name two statements re-export from
different modules keeps the old lookup.

Sync re-opens a barrel's re-exported names when the module they go
through is deleted or added, as it already did for the names an importer
binds, so a synced graph keeps matching a fresh index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:18:47 +00:00
Colby MchenryandClaude Opus 5.5 32b839acae fix(c,cpp): a name in C or C++ code outside tests links to what the file's own includes declare (#2684)
PR #2675 narrowed a C or C++ test's same-named candidates to the ones its
translation unit declares. Production code now gets the same rule:
protobuf's Python extension called the copies of upb's C API that the PHP
extension bundles in php-upb.c, and its Java generator's calls of the free
HasHasbit() went to ImmutableFieldGenerator::HasHasbit, a method beside the
caller.

Refinements the wider scope needed:
- a source implements the same-stem header beside it, when it includes one:
  pyext/message.cc is no implementation of google/protobuf/message.h;
- a header's own overloads reach the definitions its source holds:
  conformance/binary_wireformat.h's template Varint calls the .cc's;
- narrowing never leaves a call with only functions its arguments can't
  fill, past one outside the unit that they can: glog's three-argument
  GetStackTrace(...) is not utilities.h's GetStackTrace(). This also mends
  9 breakpad unittest calls #2675 had narrowed the same way;
- nor, for a C call, to definitions only a flag nothing sets compiles,
  past one the build without it does: that stays #2615's choice.
A file-level "call" (a macro, or a declaration read as a call) is left as
it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:12:26 +00:00
Colby MchenryandClaude Opus 5.5 c58f0417c6 fix(swift): a call written after try! links what it calls on Windows (#2683)
The Windows kernels read the `!` of every `try!` as a logical not, so
`try! Message2(data: d)` became a call of `! Message2` that never resolves,
and a call through a receiver lost it: `try! Settings.Defaults.load()` was a
bare `load`.

The cause is the grammar's C, not the walker. tree-sitter-swift 0.7.3's
external scanner steps aside for the `!` of `try!` through a 64-bit mask
whose entry is built as `1UL << FAKE_TRY_BANG`, bit 32. `unsigned long` is 32
bits on Windows and MSVC folds the overflowing shift to 0 (warning C4293),
so the scanner never stepped aside: `try` parsed alone, then a prefix `!` on
the callee. macOS and Linux have 64-bit longs, and clang's wasm32 build folds
the shift to bit 31 (`_directive_endif`, valid at every expression start),
so the wasm and the other kernels have always read `try!` right.

The kernel now compiles the crate tarball's src/ itself, from
codegraph-kernel/grammars/swift, with upstream 0.7.4's one-line fix (`1ULL`),
as it already does for the Kotlin, Lua, Scala and Dart grammars. The patch and
its provenance are in docs/grammars/tree-sitter-swift.patch and .md. parser.c
is unchanged, so the node-kind and field tables still match the wasm, which
is untouched.

TortureTry.swift pins calls after try!, try? and try on both engines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:49:17 +00:00
Colby MchenryandClaude Opus 5.5 22e9f7b337 fix(go): variables declared in a var ( … ) block are indexed (#2682)
tree-sitter-go wraps the specs of a var group in a var_spec_list node,
unlike a const group's, which sit directly in the declaration. Both
extractors read only the specs directly inside a declaration, so every
variable declared in a var ( ... ) block was missing from the graph: no
node, no call or construction recorded from its initializer, and nothing
for code that reads it, or for a call made through it, to point at.

Each member of a var group is now a variable, as one declared on its
own already was, with its own doc comment or the group's, and its
initializer walked under it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:23:07 +00:00
Colby MchenryandClaude Opus 5.5 16d1c95f92 fix(extraction): a build folder inside src/ is indexed for its TypeScript, JSX, Vue, Svelte and Astro files (#2681)
The default ignore list skipped every folder named build as build output,
so a JS/TS feature kept in one, like luci-go milo's src/build/, was never
indexed and the routes that lazily load its pages linked nothing.

A build folder below src/ is now walked, and its hand-written source
(.ts .tsx .mts .cts .ets, .jsx, .vue, .svelte, .astro, never .d.ts) is
indexed. What a build step may have written there, JavaScript and every
other type, stays out, as does every build folder outside src/. JVM
packages named build keep every file (#1642). The project's own root
rules still decide first: an exclude excludes the folder, and re-including
it (!src/build/) keeps every type, as before.

The rule reads paths only and lives in the two default matchers every
scope consumer builds on, so the full index, the git-status sync, scoped
sync and the watcher share it (#1728).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:10:40 +00:00
Colby MchenryandClaude Opus 5.5 6e68a11beb fix(go): a constant in a const ( … ) group keeps its own doc comment (#2680)
Both extractors read every member's docstring from the comment above
`const (`, which documents the group. A constant documented inside the
group, like gin's ErrorTypeBind under "ErrorTypeBind is used when
Context.Bind() fails.", stored no docstring, or the group's comment
instead of its own.

A member's own doc comment, read with Go's doc comment rules, is now its
docstring. A member without one keeps the group's comment, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:01:42 +00:00
Colby MchenryandClaude Opus 5.5 f43432c86a fix(go): a comment directive like //go:embed is not part of a declaration's doc (#2679)
go doc leaves comment directives out of a doc comment's text: a // comment
with no space after the slashes that is //line, //extern or //export
followed by text, or that opens with a lowercase word, a colon and a
lowercase letter or digit, like //go:embed static or //nolint:errcheck
(go/ast's isDirective). Both extractors kept them, so prometheus's
testsFs had the docstring "go:embed testdata", etcd's store.restore
"nolint:unparam", and a doc comment with a directive under it ended in
that directive.

Go now drops directives from the docstring's text through a Go-only
extractor option (docstringSkipsDirectives in TS; the kernel's Go
docstring helper becomes preceding_go_doc_comment, which applies all
three Go rules). A directive still counts as a comment when deciding
where the doc comment starts, as in go/parser, so a declaration whose
only comment is a directive has no docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:45:40 +00:00
Colby MchenryandClaude Opus 5.5 23f728fac2 fix(go): a comment a blank line separates from a declaration is not its doc (#2678)
Go's doc comment, the one go doc shows (go/parser's lead comment), is the
comment group that ends on the line right above a declaration: comments
on consecutive lines form one group, and a blank line ends it. Both
extractors joined every comment above a Go declaration instead, so a
section banner, a TODO or commented-out code above a blank line became
part of the declaration's docstring, or its whole docstring when the
declaration had no doc of its own.

Go now keeps only that group, through a Go-only extractor option beside
the trailing-comment one (docstringSkipsDetachedComments in TS,
preceding_docstring_skipping_trailing_and_detached in the kernel). A
comment that ends on the declaration's own line documents nothing, as
in go doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:28:12 +00:00
Colby MchenryandClaude Opus 5.5 22d420ec8a fix(react): a name the file destructures at its top renders no JSX child (#2677)
Since PR 2676, a tag whose name the parent, or a function around it,
destructures renders only a component that function declares inside
itself. A name the file destructures at its top was left out, because no
function's code holds it: refine's pages take `const { Title, Text } =
Typography;` from antd once, above their components, and every `<Title>`
and `<Text>` in them linked to another example's `Title` or `Text`
component by name.

The pass now reads the destructuring patterns the file declares outside
every brace (`topLevelPatterns`, on the code-only view), so in no
function, class or block, and never a top-level callback's parameter.
Only braces are counted: JSX text may hold a stray parenthesis or
bracket, never a brace that opens no expression, and `jsxCode` returns
null for a file whose braces don't balance, which then binds nothing
here. A tag that no function in its scope chain binds, but that such a
pattern binds (`bindingElementAt`, so not a `require(...)` or `import(...)`
declaration), renders only a component the outermost of those functions
declares inside itself, else nothing.

Fresh before/after indexes on 31 repos (main 24ea3c54): 177 jsx-render
edges removed, all in refine-examples (94 to one example's `Text`, 83 to
another's `Title`), and every tag of each is a module-level destructured
local by the TypeScript checker. Nothing else changes; 30 repos are
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:04:13 +00:00
Colby MchenryandClaude Opus 5.5 24ea3c54b2 fix(react): a name a component destructures, or a function around it binds, renders no JSX child (#2676)
#2442 made a tag the parent binds itself, as a `const` or a parameter,
render only a component the parent declares inside itself. Destructuring
was left out, as name-matcher leaves it out for a bare call (`const { t }
= useI18n()` is that function more often than not), so a destructured tag
still linked any same-named component in the repository. For a tag that
is the wrong default: what a component destructures is a component its
props or a library hand in, which is no node here.

- refine's layouts, `({ children, Header, Footer, Sider, OffLayoutArea })
  =>`, rendered other examples' `Header`, `Footer`, `Sider` and
  `OffLayoutArea`; `const { Title } = Typography` (antd) and `const {
  Link } = useRouterContext()` rendered other examples' `Title` and `Link`.
- excalidraw's example app, `const { Sidebar, Footer, WelcomeScreen, … } =
  excalidrawLib`, rendered its own `ExampleSidebar.tsx` for the library's
  `Sidebar`, and `Footer.tsx` though the library exports `FooterCenter` as
  `Footer`. Its other tags landed on the library's components by luck.

A tag now checks the parent's code through its first tag for a
destructuring pattern that binds the name (`destructures`, read off the
code-only view): a declaration's or a parameter's, nested patterns, rest
elements, rename targets and array patterns included. A rename's key, a
default value and a type literal after a pattern bind nothing, nor does an
object argument or a control-flow head, and a declaration of `require(…)`
or `import(…)` binds the module's own export, which links as before.

The same check, and #2442's `const`/parameter check, now also reads the
functions around the parent: excalidraw's `renderExcalidraw` and
`renderTopRightUI` render what `ExampleApp` destructures. The function
that binds the name is the one whose own components a tag may still
render (`declaredInside`), so a helper rendering a component its enclosing
function declares (binner's `recursiveTreeItem` → `StyledTreeItem`) keeps
its edge.

Fresh before/after indexes on 31 repos (main a50104c8): 24 jsx-render
edges removed (excalidraw 14, refine-examples 10), every one graded
all-local by the TypeScript checker (each tag a destructured local);
15 targets were wrong, 9 right by luck. One of them, ExampleApp →
ExampleSidebar's `Sidebar`, comes back with `via` ExampleSidebar, the
default import that renders it, which the wrong `<Sidebar>` edge used to
hide. No other edge, node, ref or file changes; 29 repos are
byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:38:59 +00:00
Colby MchenryandClaude Opus 5.5 bb8a0f732b fix(c,cpp): a name in a C or C++ test links to what the test's own includes declare (#2675)
When several files declare a name a C or C++ test uses, the test now links
to one its translation unit declares, when there is one: a definition in its
own file, in a file it includes (directly or through other includes), or in
the source file that implements such a header (the same-stem file that
includes it), unless that source keeps the definition to itself (a `static`,
an unnamed namespace, a class it declares). Before, the candidates were
ranked by directory and index order, so a test took whichever namesake came
first:

- protobuf's C# generator tests called test_util2.h's
  `TestUtil::TestSourceDir()`, a test suite they never include, instead of
  the `TestSourceDir()` googletest.h declares;
- protobuf's upb and hpb tests left `upb_Arena_New()` and the rest of upb's
  C API unlinked: the copies bundled for PHP and Ruby won the ranking and
  were then rejected;
- rocksdb's c_test.c left `rocksdb_open()` and the rest of the C API in
  db/c.cc unlinked, and its histogram test's `clock->SleepForMicroseconds()`
  went to emulated_clock.h's `EmulatedSystemClock`, which it doesn't include.

The narrowing applies to test files only, to the exact-name strategy, typed
receivers (resolveMethodOnType), and the class-name and receiver-word
strategies of matchMethodCall. When the translation unit declares none of
the candidates, as when a test's includes don't resolve (jemalloc's tests
include a generated header), the candidates stay as they were. A name a
test writes alone (no receiver, no qualifier) is narrowed only to what C++
finds for it outside a class: a function, a namespace-scope type or a
constructor, never another class's method or nested type, and a call the
extractor recorded without the receiver it is written on is left as it
was. The qualified-name strategy is unchanged.

Validated on main 3695818f (site-keyed edge diffs, every group triaged):
rocksdb +1,442 / 47 retargeted / -12, protobuf +2,316 / 55 / -67,
fmt +33 / 40, breakpad +13 / 14, glog +22, leveldb +10, llm.c 6
retargeted; jq, tokio, excalidraw, okhttp and typeorm byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:22:03 +00:00
Colby MchenryandClaude Opus 5.5 bf6995e911 fix(js): a JavaScript file's import of a TypeScript module links that module (#2674)
An extensionless import from a `.js` or `.jsx` file of a TypeScript module,
like mastodon's `import AudioModal from './audio_modal'` in modal_root.jsx
beside audio_modal.tsx, never resolved by path: the import resolver's
javascript and jsx extension lists held only JavaScript extensions, while
the typescript and tsx lists already try `.js`/`.jsx`. In a codebase
moving to TypeScript those imports were matched by name instead, so an
import under another name linked nothing, and a repeated name could link
the wrong file (mastodon's `<IconButton>` and `<Status>` tags rendered
other same-named components than the ones each file imports).

The javascript and jsx lists now try `.ts`/`.tsx` (and their index files)
after their own extensions, as a bundler and tsc's allowJs resolve them.
JavaScript stays first, so a `helpers.ts` beside `helpers.js` does not
take its importers, and never `.d.ts`, which is no module a JavaScript
file runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:12:04 +00:00
Colby MchenryandClaude Opus 5.5 ab6ec218ff fix(js,ts): a function value imported from the project links only to what its import binds (#2673)
A function passed as a value whose name the file imports from its own
project still fell back to the project's one function of that name
whenever the import resolver bound the name to something that is not a
function: outline's `isCloudHosted` constant landed on the server's
`isCloudHosted()` check, its `Star` model class on the `<Star>` icon,
`import * as Slack` on the Slack settings component, and topcoder's
`import TCO21 from './themes/TCO21.scss'` on a route component.

matchFunctionRef's unique cross-file fallback now also declines when a
project import binds the name to something else (importBindsOther): a
namespace import, an asset import (stylesheet, image, GraphQL, JSON,
font, media; judged by the specifier's extension), or an import the
import resolver binds to a node that is not a function or method. A
wrapper declared beside the namesake (`export default
styled(Disclosure)`) and a lazy loader (`lazy(() => import(...))`)
still lead to it, and an import the resolver can't follow at all keeps
the fallback.

Follow-up to #2671.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:43:16 +00:00
Colby MchenryandClaude Opus 5.5 a50104c895 fix(react-router): read every table a route-building function returns, and the one behind useMemo (#2672)
The route-table pass (`returnedTable`) took the first `return [` anywhere in
a route-building function's body for its table:

- An early guard's `[]` (`if (!user) return [];`) hid the real table.
- A callback's `[]` did too: devanshthakker15/BANKFORM1's `generateRoutes`
  returns `[]` from a `.forEach` callback before its own table.
- A menu that a helper inside the function returns could be read as routes.
- Of `if (admin) return [ … ]; return [ … ]`, only the first branch was read.

A function that returns another function's table (`return buildRoutes()`)
was not followed, and neither was `useMemo`, which hooks-based routers wrap
their table in.

Now `returnedTables` reads what the function's expression body gives, or
what each of its own `return`s gives (`ownReturns`). It steps over the
bodies of arrows, `function`s and methods written inside it, found by a
brace matcher tolerant of JSX text: in `blockEnd` and `opensString`, a quote
right after a word is an apostrophe. `heldTable` reads parentheses around a
value, and reads `useMemo(() => getRoutes(user), [user])` and
`useMemo(getRoutes, [])` as the function's tables. `tableNamed`,
`exportedTable` and `declaredTable` now return every table they find.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:31:31 +00:00
Colby MchenryandClaude Opus 5.5 b8f81e2c8e fix(js,ts): a function value imported from a package no longer links a project function of that name (#2671)
A function passed as a value (`styled(Link)`, `createContext({ onClose:
noop })`, `Chart.register(Legend)`) whose name the file imports from a
package is that package's function. matchFunctionRef still bound it to
the one project function of that name whenever there was exactly one:
outline's react-router-dom `Link` landed on an email template's
`Footer.tsx:Link`, cord-field's lodash `noop` on a test's own stub.

The cross-file fallback now consults the same out-of-repo guard the
call and value paths use (isOutOfRepoBinding). A same-file declaration
still wins (a local that shadows the import is what the name means
there), a project import still resolves through its import, and a
specifier no package.json declares may be an alias and stays the
project's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:11:07 +00:00
Colby MchenryandClaude Opus 5.5 1aebd3a30f fix(react-router): a route that renders <Outlet /> renders nothing of its own (#2670)
A route with no element renders an `<Outlet />`, and JSX routes already read
`element={<Outlet />}` that way. Route objects did not:

- `element: <Outlet />` and `Component: Outlet` made `Outlet` the route's
  page and the layout of every route inside it. Those `layout:Outlet`
  references link nothing: 93 failed rows on Medusa's admin dashboard, 106
  on Mercur's, 87 on mercurjs/vendor-panel.
- A `lazy` loader returning `{ Component: Outlet, loader }` (Medusa's `:id`
  routes import their page module only for its loader and breadcrumb) read
  as unreadable, so the route fell back to that module's page, which became
  the layout of the routes inside: a product's detail page drawn around its
  variants' pages.

Such a route object is now an `outlet` scope. It is a route at its own
address, so a navigation there still lands, and it sits inside the layouts
around it, but it has no page reference and is no layout. A page inside at
the same address claims the address as before, and a `path: ''` one only
groups its children at its parent's address. `lazyRouteReference` returns
`Outlet` for a loader that hands it back, and the JSX branch drops it the way
it drops `element={<Outlet />}`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:59:29 +00:00
Colby MchenryandClaude Opus 5.5 3695818fa2 fix(sync): an import of a folder further up links its index file when it appears (#2669)
An import that names a folder only through where it is written (`.`, `..`,
`../..`) is parked under no key, so sync tries each where it is written when
files are added (#2528). That lookup listed `.`, `./`, `..` and `../` only, so
`import { Excalidraw } from "../.."` in excalidraw's tests, or any import of a
folder two or more levels up, stayed unlinked after its folder's `index` file
was added or restored, though a fresh index links it. It now lists the folder
up to twelve levels above, with or without the trailing slash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:37:06 +00:00
Colby MchenryandClaude Opus 5.5 654a853f5a fix(react-router): read the table a function returns when a variable hands it to the router (#2668)
Medusa's admin dashboard builds its router in a class's `render()`:
`const routes = getRouteMap({ settingsRoutes, coreRoutes })`, then
`createBrowserRouter(routes, { basename })`. `getRouteMap`, imported from
its own module, returns the literal table. The route-table pass
(`tableRoutes` in frameworks/react.ts) read a variable only when it held
the literal itself, so none of the 221 routes existed, and the dashboard's
`navigate()` calls and `<Link>`s led nowhere.

- `declaredTable` now reports a value initialized with a call
  (`getRouteMap({ … })`, `await loadRoutes()`) as the function to follow,
  and `tableNamed` / `exportedTable` follow it to the table it returns,
  local or imported. `export const routes = buildRoutes()` and
  `export default buildRoutes()` are read the same way.
- Of several declarations of a name in a file, the one in scope at the use
  is read (`visibleAt`). Scope comes from the graph's functions; a
  function-local declaration has no node of its own, so the declarations
  are read from the text. Another function's `const routes = getMenu()` is
  that function's own and is never followed. An exported name is a
  top-level one.
- What the function's parameters spread in (Medusa's `...coreRoutes`,
  filled from plugins) stays unread: no declaration in scope names it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:22:57 +00:00
Colby MchenryandClaude Opus 5.5 437b5c329f fix(sync): an import links an added file whose name a popular import shares (#2666)
Sync retries a failed import by what an added file can be imported as (its
name, its stem, its folder) and skips a key more than 500 failed imports
share, as noise one file cannot answer. A path import is parked under its
path's stem, though, and a package's imports share that stem with every file
of the name: `utils` is the stem of every `jotai/utils` and `@scope/pkg/utils`
as much as of a project's own `./utils`, and `assert` the name of every binding
of `import * as assert from 'assert'`. In a large project those crowded the key
past the ceiling, so a project's own `utils.ts` added after its importers were
indexed, or restored after a delete, never linked them: folo's
`modules/settings/utils.ts` and `components/ui/modal/stacked/hooks.ts`, and
vscode's `base/common/assert.ts`.

A key past the ceiling is now looked through for the imports that could name
an added file, and those are retried. A JavaScript or TypeScript import names
a file by its module (the path branch of resolveViaImport, shared with it as
jsModuleFile), by a framework alias, or by the file's own name. What that
accepts is no noise, so it is held to the module ceiling, as the specifiers
that resolve to an added file already are: bitwarden imports its
account.service from 724 files. An import in another language is not
accepted, so a crowded key there is skipped as before; a key within the
ceiling is retried whole, as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:58:56 +00:00
Colby MchenryandClaude Opus 5.5 5c1e55f44c fix(go): a call on a package-level variable or constant links through the type it is declared with (#2667)
Nothing read the declaration of a Go variable or constant declared at the
top level of a package (the scope reader skips them, and the pattern scan
reads only the calling function), so a method call through one was matched
by the method's name: etcd's `var lg *zap.Logger` made `lg.Panic(...)` a
project logger's `Panic`, prometheus's protobuf `xxx_messageInfo_*` values
reached project `Marshal` methods, and kubernetes' registry tests' calls on
each package's `var Strategy = fooStrategy{...}` reached another package's
exported `Strategy` type.

matchGoPackageValueCall reads a same-package `variable` or `constant` node's
spec when the call's receiver is a plain name that no local or parameter
binds and no import names: a written type, a composite literal's or a
conversion's type, or for a constant alone in a `const ( ... )` group the
spec above it. A project type gives its own method (0.9) through the
package that declares it; a type or value from outside the project, a
predeclared type or a type literal gives nothing. A value a project
function returns, an untyped constant, declarations that differ between
build-tag files, and a project type whose methods aren't found are left to
the strategies below. A `package foo_test` file in the directory is another
package.

A/B on main 90d6501b, same kernel for both arms, full index per arm:
- gin: 4 guesses now typed at 0.9.
- prometheus: 59 dropped (gogo-protobuf `xxx_messageInfo_*`, `sync.Pool`
  values), 40 new links (`RoleEndpoint.String()` and its siblings).
- etcd: 18 dropped (`var lg *zap.Logger`, a cobra command), 43 new links
  (`var display printer = &simplePrinter{}`), 3 now typed.
- harbor: 2 dropped (`var handler http.Handler`), 24 new, 38 retargeted
  (`var configManager *cfgPkg.CfgManager`), 34 now typed.
- kubernetes: 46 dropped (outside-typed values), 260 new, 405 retargeted
  (each registry package's own strategy type), 430 now typed.
fmt, llmc and typeorm are identical. Every dropped link, grouped by
receiver, and every retargeted owner pair was checked against the
receiver's declaration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:46:07 +00:00
Colby MchenryandClaude Opus 5.5 a6cfb52371 fix(sync): an import a barrel passes on under another name relinks when its module gains it (#2665)
A sync that gives a module a definition retries the failed references
waiting for the names the module declares, and rebinds the edges into the
names that changed (CG-33). An importer that reaches the module through a
barrel passing it on under another name waits under neither: matx's
`export { default as MatxLoading } from './MatxLoading'` hands
MatxLoading.jsx to `import { MatxLoading } from 'app/components'`, a name
the file never declares. That import and the calls through it stayed
failed, and where a name match had taken the name elsewhere while the
module lacked it (vben's `alert`, which its alert barrel passes on from
`vbenAlert`, onto the `alert.vue` component), the edge stayed there, until
the importer changed or the project was indexed again.

reopenReferencesThroughBarrels now records each importer below a barrel
with the names the barrel passes the changed files on as, and re-opens that
importer's failed references through those names and, for the names the
files never declare, its edges bound before the sync resolved anything, as
the added-file path does. A declared name stays the retry's and the
rebind's, which cap a common one. The per-importer lookup replaces the
repo-wide retry by the passed-on names, whose per-name ceiling skips a name
as common as `alert`; the barrels' module keys are still retried for lazy
routes. passedOn, which the added-file path shares, now also reads an
import a barrel exports again, with the names it exports it as (`import
Card from './Card'; export { Card as AppCard }`), which only the lazy-route
walk followed before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:05:15 +00:00
Colby MchenryandClaude Opus 5.5 90d6501b09 fix(go): a call of a standard method name like err.Error() links to its receiver's declared type, never to one it shares a word with (#2664)
A Go call of a standard method name (GO_STD_METHODS: Error, String, Err,
Lock, Len, Header, ...) on a receiver whose type wasn't worked out was
guessed by a word the receiver shares with a type's name: kubernetes'
`err.Error()` linked to `notRegisteredErr::Error`, prometheus's to
`ParseErr::Error`, etcd's `leaderID.String()` to `MoveLeaderRequest`, and
a receiver declared as a type from outside the project to a project type
of its name (etcd's `var pendingMu sync.Mutex` to its concurrency `Mutex`).

In matchMethodCall, for a standard method name on a plain Go variable:
- The receiver's declaration in scope (goLocalDecl, the scope reader)
  decides, over the unscoped pattern scan: a project type's own method,
  through the package that declares it; nothing for a predeclared type, a
  type from outside the project, a type literal, a value an outside
  package hands out, or a declared type that lacks the method.
- Otherwise a guess needs the receiver to name the owner type itself,
  case and a trailing number aside (`id` an `ID`, `urlsMap` a `URLsMap`):
  in Strategy 3 through receiverNamesOwner, and in Strategy 2, which took
  any method of the owner's file whose name contained the type's
  (`status` reached `RuntimeStatus::String` beside a `Status` type).
- Only a declaration the scope reader finds rules a call out. The pattern
  scan reads back for the name without block scope and can find another
  declaration of it, like a test table's `version string` above
  `version, _ := parse(...)`; valid Go calls no method but `Error` on a
  predeclared type, so such a read says nothing.

A/B on main b4e10138, same kernel for both arms, full index per arm:
- gin: 17 guesses dropped; 14 calls newly typed (`c.String(...)` in
  `func(c *gin.Context)` handlers).
- prometheus: 265 dropped, 89 newly typed, 6 retargeted.
- etcd: 335 dropped (23 of them typed links of `sync.Mutex` and
  `sync.RWMutex` values to project namesakes), 52 newly typed, 7
  retargeted.
- harbor: 174 dropped, 6 newly typed, 6 retargeted.
- kubernetes: 2489 dropped, 241 newly typed, 77 retargeted.
No link of any other method name changed, and the fmt, llmc and typeorm
controls are identical. Of 132 dropped links sampled, 3 were right
(locals typed by a project call's result, which no reader types yet).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:51:16 +00:00
Colby MchenryandClaude Opus 5.5 0d33925aa3 fix(ts): a method whose name has a $ resolves through its receiver's type (#2662)
The method-call pattern read the method name as \w+, which has no $, so
a JS/TS call like bitwarden's this.organizationService.organizations$(id)
or vscode's RPC this._proxy.$acceptModelChanged(…) matched no method-call
shape and linked nothing, however well its receiver was typed. For the
JS family the method part now admits $; the receiver part is unchanged,
so RxJS receivers like this.destroy$.next() stay out of name guessing.

A/B on main b4e10138: vscode +1514 (mostly RPC calls onto their shape
interfaces), bitwarden +2116, qwik +68, none removed or retargeted; 12
other JS/TS repos byte-identical, Vue 2 options-API apps included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:44:17 +00:00