mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-14 21:13:11 +08:00
7324faf69fd951effef5e4f2f765fcc8653fe17b
532
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7324faf69f |
fix(rust): a call on a field of self reaches the method of the field's declared type (#2719)
A Rust `self.field.m()` call was resolved by the last segment of the field's type name alone. `inner: multer::Field` linked to axum's own `Field::name`, `std: std::time::Instant` to tokio's `Instant` (the calling method itself), `inner: std::sync::Mutex<…>` to tokio's loom mock or async `Mutex::lock`, and a field generic over the impl's `S: Store` to nothing. The field's type is now read the way field values already are: from the struct's declaration, through the wrappers, by the `use`s of the struct's file. A struct's own parameter is known by the bounds that the impl around the call gives the parameter it is instantiated with (`struct Worker<S>` under `impl<S: Store> Worker<S>`). The method is the one the typed receiver path picks. The plain-name reading stays only where the field's type can't be read. A call on a std or dependency value reaches a project trait's impl for its type only when the impl is for that type. tokio's `impl Kill for Child` in process/windows.rs is for its own `struct Child`, not `std::process::Child`. The impl's type is read as the impl writes it: gleam's `impl LowestVersion for pubgrub::Range<Version>` is for pubgrub's `Range`. A/B with fresh indexes against main on axum, serde, ripgrep, clap, dioxus, tokio and gleam, every changed edge triaged: 361 calls linked that were not (fields bounded by the impl's traits, dioxus's signal fields, trait objects), 104 removed (calls on std and dependency fields, and 5 on tokio values whose methods sit inside `cfg_*!` macros), 59 moved to the right type of a shared name, 2,844 kept at a higher confidence; 62 fewer self-loops and none added. gin, serilog, flask and express are byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a33040f786 |
fix(js,ts): an import of a package the repository declares itself links to that declaration (#2718)
A `declare module 'mammoth' { ... }` in a script .d.ts declares the module
outright, and TypeScript takes it before any file the specifier resolves to.
Nothing mapped a package name to a file in the repository, so an import of
such a package linked nothing, or, where the out-of-repo guard did not fire
(VS Code's extensions list no `vscode` dependency), a project namesake. A
bodiless function in an ambient context produced no node either, so
`convertToHtml` had nothing to link to.
- ambient-modules.ts: a token scanner for `declare module` blocks, a
per-context index of the project's declaration files, and the lookup the
import resolver makes: named, default (`export default`, `export =`),
export-clause and namespace-member imports, by position in the block.
- The import resolver consults a script declaration before a file a path
alias maps the specifier to (copilot's `paths` shim), and the import's
module reference and namespace or default binding link the declaring file.
- Extraction, both engines: a function_signature under `declare`, in
`declare global`, at a declaration file's top level or directly in its
`declare module` body is a function; never in a namespace, nor in an
ordinary module file's `declare module`, an augmentation.
- A module's function is reached from another file only through an import.
- A type merged across the files declaring one module is no single
declaration when a receiver is typed.
- Sync re-opens the importers of a package a changed declaration file
declares.
Augmentations, wildcard patterns, shorthands and test-fixture declarations
are left alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
642c7bb3a5 |
fix(python): attribute calls follow the type the class body, a factory or a base gives the attribute (#1926)
Python calls through an attribute reach the method the code gives that attribute: `self.sink.stop()` follows `self.sink = Sink()`, a `sink: Sink` annotation, a typed `__init__` parameter, a factory's return type or what every `return` in it builds, and a base class's `__init__` in another file. Calls straight on a factory's result (`Client.from_env().send()`) resolve the same way, and a sync re-opens these answers when the factory or base they were read from changes. The native Python extractor now keeps a call's receiver text as the wasm one does, so `self.data.append(1)` is never a bare `append` that matches an unrelated project function. This includes all of PR 1704. Reworked from evidence-or-silence, which dropped about 3,000 correct Django links (`self.client.get()`, `self.engine.render_to_string()`). The reader now has three answers. A project class that has the method: that method. Evidence that rules project methods out: no edge, for a builtin, a class from outside the project built in a method or named by an annotation, an attribute only an outside base can give (Django's `TestCase` in an app), or a class without the method whose bases are all known. Nothing typed: the call is guessed by the name of its last link, read as written, as any receiver is, but only for an owner whose name holds the link's head noun (`self.session` for `SessionBase`, not `database.group_shopping_lists` for `GroupRepositoryAIProvider`) and never as the one method of a name; the guess records the files the reader looked at, so a sync re-opens it too. A class-body field an outside class builds (`author = models.ForeignKey(Author)`) may be a descriptor, so it is no evidence. A chain through an imported module (`os.path.exists()`) is the module's. In the shared scoring, a receiver that spells an owner's whole name (`client` for `Client`) outscores one that only shares its word (`RedisCacheClient`). A call through an imported value's attribute chain (`app.jinja_env.filters.keys()`) no longer links to the value's `jinja_env`. A/B against main with fresh indexes, every changed edge triaged, sites matched by position since the extractor now names these calls by their whole chain. Django: 3,317 calls linked that were not (`self.client.force_login()` to `ClientMixin`, `User.objects.create_user()` to `UserManager`, `self.stdout.write()` to `OutputWrapper`), 127 moved, nearly all to a more precise target (`self.site.register()` to `AdminSite.register` rather than the `register` decorator), and 134 removed: main's bare-name links on builtin values (`value.lower()` to the template filter, `.encode()` to a test password hasher) and calls on expressions such as `(q1 | q2).order_by()`, which now go unresolved as they do in the wasm engine. flask: 32 linked, 4 moved to `JSONProvider`. fastapi: 58 linked. mealie: 740 linked. Guesses still wrong, as main makes them for a plain receiver of the same name: fastapi's `request.headers.get()` to a telemetry `_HeadersGetter`, and about 20 of mealie's repository attributes to a controller. Go, C#, Ruby, Swift, Kotlin, Java and TS repositories are byte-identical, except excalidraw's 5 `props.onChange()` calls, which move between two unrelated `Props` interfaces. Indexing CPU: Django +7%, mealie +5%, fastapi flat; wall time unchanged within noise. Full suite on the merged tree: 7,999 passed, 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4286083a84 |
fix(rust): a for-loop variable or a tuple pattern's name has the type it is bound from (#2717)
A Rust `for` loop's variable, and a name a tuple pattern binds (`for (k, v) in &map`, `let (tx, rx) = mpsc::channel(8)`), had no type the typed receiver path could read, so calls on them fell to the older receiver inference and the name strategies. tokio's 198 `tx.send(…)` calls on channel senders went to the internal `chan::Tx::send`, and 100 calls on the receivers to `chan::Rx`. The scope reader now records what a `for` loop iterates, and gives the plain names of a top-level tuple pattern their place in it. A loop's variable is an item of what it iterates: a std sequence's element, a std map's `(K, V)`, a slice's, a std iterator's or an `impl Iterator<Item = T>`'s item, through `&` and the pointers that deref to what they hold. The std adapters that keep the items (`.iter()`, `.rev()`, `.skip(n)`) or project them (`.keys()`, `.values()`, `.enumerate()`) are looked through only where what they are called on is read, so a project method of one of those names is read from its own signature. A tuple pattern's name is the matched tuple's field at its place. A field access (`self.items`, `opts.config`, `pair.0`) has the type the receiver's struct declares for the field. A free function called through a module that a `use … as` renames was looked up by the alias: tokio's loom tests' `oneshot::channel()` under `use crate::runtime::tests::loom_oneshot as oneshot` read the return type of `sync::oneshot::channel`. The path's head now goes through its `use`, and the project's modules are walked along it. A/B with fresh indexes against main on axum, serde, ripgrep, clap, dioxus, tokio and gleam, every changed edge triaged: 394 calls linked that were not, 86 removed (calls on std or dependency values, tokio values whose read and write methods come from macro-declared extension traits, derived `Clone`s, fields that hold functions), 404 moved to the declared type's method, 625 kept at a higher confidence. gin, serilog, flask and express are byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e043efbc84 |
fix(resolution): a call through a class name reaches that class, not one whose name contains it (#1935)
A call through a class name, `Logger.log()`, or through a receiver named after one, `logger.log()`, now binds to that class itself: its own method, else the nearest one a declared supertype has. Before, the method was any one in the class's file whose qualified name contained the class's name, so a `FileLogger` declared first took every `Logger.log()`, and Kotlin's `Foo.create()` went to `FooBar`'s. Reworked from the exact-owner rule alone, which lost inherited methods (Django's `form.is_valid()` on `Form(BaseForm)`, Alamofire's protocol methods). Also in this change: - A class declared inside a function is named only there: a call from anywhere else no longer reaches a class a test declares in its body, through the class name, the receiver's name, or the method-name fallback. Those methods were never in the running, and the one method such a filter leaves is still only a guess by the receiver's name. - Production code never names a test suite's class, as the method-name fallback already held: `manager.check()` in Django's `Model._check_managers` is no test app's `Manager` model. - A Python base built by a class's factory, Django's `class Manager(BaseManager.from_queryset(QuerySet))`, names that class as the supertype, besides the factory's arguments. A/B against main with fresh indexes, every changed edge triaged. Django: 67 links added (model instances reaching `Model.save`, inherited lookups and expressions), 40 removed (links into test-local classes from outside their function, and one polymorphic manager call), 263 retargeted: about 170 to the right class (`user.has_perm` to `PermissionsMixin` rather than `AnonymousUser`, `parser.parse` to the template `Parser` rather than `MultiPartParser`, `field.get_lookup` to `RegisterLookupMixin`), about 90 from one guess to another, and about 20 worse, where a receiver named after a model holds something else (`session.save()` on a session store now guesses the `Session` model). flask: one fix (`app.get` to `Scaffold.get`), 3 wrong links removed. Alamofire: one fix and 3 protocol-typed locals that now guess the `Adapter` class. zod, excalidraw and spring-petclinic: higher confidence on the same targets. gin, cobra, express, eShopOnWeb and jekyll are byte-identical. Full suite on the merged tree: 7,908 passed, 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f76021db22 |
fix(rust): a local holding a method call's value has the type the method returns (#2716)
A Rust local bound to a method call (`let server = b.port(80).build()`, `let s = cfg.load()?`, `let conn = c.connect().await`, `if let Some(c) = arg.get::<Completer>()`) had no type the typed receiver path could read, so calls on it fell to the name strategies. Those strategies did not read `?` on a returned `Result`, a `self` method's value or a turbofish, and picked a same-named method of another type. The value is now the return type of the method the call reaches on its receiver's type, read from that method's signature. A receiver is a local, `self`, or another such call. `.await` hands out an `async fn`'s return type (read off the source: the extractor's async flag is never set for Rust) or an `impl Future`'s `Output`, and an `async fn` not awaited is a future, left unread. A method's own type parameter is the call's turbofish argument. A parameter the call doesn't write stays opaque: `Standard<W>` is a `Standard`, but a value that is `W` itself is unread rather than its bound. A trait's provided method returning `Self` gives the receiver's own type. A type with two impls of one trait, `Encoder<Bytes>` and `Encoder<&[u8]>` or `Service<IncomingStream>` and `Service<Request<B>>`, was ambiguous for a typed call. The impl whose trait argument is the call's first argument's type now wins. A/B with fresh indexes against main on axum, serde, ripgrep, clap, dioxus, tokio and gleam, every changed edge triaged: 536 calls linked that were not, 69 removed (calls on std or dependency values a method returns, and tokio values whose read and write methods come from macro-declared extension traits), 50 moved to the declared type's method, 565 kept at a higher confidence. gin, serilog, flask and express are byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
23b5ca1b43 |
fix(rust): a call on a local reaches the method of the type it is declared with (#2715)
A Rust method call on a local variable or a parameter (`opts.build()`) was matched by the method's name whenever the receiver's declaration wasn't one of two unscoped line patterns. dioxus's `Commands::Build(opts) => opts.build()` lost its link once the build module's `BuildRequest::build` shared the name, and calls on std or dependency values linked to project namesakes: `cx.waker()` on a `Context` to tokio's `CachedParkThread::waker`. The receiver is now typed by the binding the call sees. The new src/resolution/rust-scopes.ts reads each file's parameters, closure parameters, lets, if-let / while-let / let-else, for and match-arm bindings with block scope. A binding's type is its written one, the value it is built from, or the variant or struct field its pattern takes. The method is the one Rust picks on that type: inherent first, then a trait impl whose trait is in scope, then a trait's provided method (a blanket impl only where its bounds are met), then Deref. `&`, Box, Rc, Arc, Pin, Cow and the lock guards are looked through, their own methods kept (one list with the self-call path's), and a project impl on the wrapper itself answers before what the wrapper holds, as it does for `self`. `impl Trait`, `dyn Trait` and bounded generics reach the trait's method or a supertrait's. Among types sharing a name, the one its path names through the project's modules wins, the path written or bound by a block-scoped `use`, else the one that has the method. A std, dependency or primitive type reaches only a project trait impl in scope, and not one that hands the call on to the type's own method of that name. A binding that writes no type leaves the call to the name strategies, which no longer take a project type from another declaration of the name. A trait's own methods carry no `pub`: isVisibleAcrossFiles lets them through for the calls this path resolved, and name guesses stay out as before. A/B with fresh indexes against main on axum, serde, ripgrep, clap, dioxus, tokio and gleam, every changed edge triaged: 4,645 calls linked that were not, 887 removed (calls on std or dependency values, project types without the method, a wrapper's own methods), 459 moved to the declared type's method, 3,669 kept at a higher confidence. gin, serilog, flask and express are byte-identical. The new code costs 0.6 to 0.9 s of CPU per full index of tokio, dioxus or gleam. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f5158fac02 |
fix(rust): a name a glob use brings in is an item the globbed module passes on (#2714)
dioxus's examples write `use dioxus::prelude::*;` and then `Element` or
`use_signal(...)`, which the prelude re-exports from dioxus-core and
dioxus-hooks: `pub use dioxus_core::{Element, ...}`, and `pub use
crate::hooks::*` through `pub use dioxus_hooks as hooks;`. The glob rule
(rustGlobCovers) only took an item declared in a file named like the glob's
last segment, so all of those went unlinked, while `use super::*` took
anything in the parent's directory and a glob over another crate's `types`
or `error` module took this crate's file of that name.
A name only globs bring in now goes through the module walk of #2702:
rustGlobItems walks each of the file's globs from the module it is written
in and looks the name up there. Two additions to the walk:
- a step through a module its parent passes on under that name
(`pub use dioxus_hooks as hooks;`, `pub use dioxus_signals::{self, *}`);
- Rust's visibility for globs: seen from inside a module (`use super::*`) a
glob takes everything; from anywhere else only what the module declares
`pub`, `pub use`s or `pub` globs. dioxus-hooks' `pub use use_effect::*`
does not pass on that module's own `use dioxus_core::*`, so the prelude
never brings in dioxus-core's `Ok` function; without this rule 146 std
`Ok(...)` calls in dioxus's examples linked to it.
A glob that brings the name in settles it, so one the walk can't follow
(a macro's module, a #[path] module) matters only when none does; then the
old module-name rule answers as before.
A/B with fresh indexes, main
|
||
|
|
e2aa5d205d |
fix(rust): a same-file path's inline module is read from its braces, not its indentation (#2713)
PR #2711 and PR #2702 landed a way each to tell which inline `mod` a
place in a Rust file is in. #2711's isInRustInlineModule scanned lines
upward for `mod <name> {` and trusted rustfmt's indentation to find where
the block closes. #2702's rustModBlocks scans the braces, skipping
strings, raw strings, char literals and comments, and keeps the result in
rustUsesOf. isInRustInlineModule now asks rustBlockAt for the innermost
block around the candidate, as rustDeclaredItems does, so there is one
answer to that question.
What changes:
- An item written without indentation inside `mod flat { … }` is found
through `flat::Flat`. The indentation rule rejected it.
- `outer::Shell` is only `outer`'s own `Shell`, not one declared in a
`mod deep` inside it. The upward scan accepted any item below the
`mod outer {` line.
- A file whose braces don't all close says nothing, as it does for the
`use` walk of PR #2702.
The A/B (main
|
||
|
|
818e780336 |
fix(rust): a trait's associated type named <T as Trait>::X or bound as Trait<X = …> links only to what it names (#2712)
A trait's associated type is named in two more ways than `Self::X`, and
neither names a module item:
- Through a qualified self, `<T as Trait>::X`. isRustNameInScope took any
associated item of the name for it. axum's `<L as Listener>::Io`, with
`L` a generic, went to `ReadyListener`'s `type Io`. A trait's own
`fn call(…) -> <Self as HandlerCallWithExtractors<T, S>>::Future;`
went to an impl's `type Future` further down the file.
- As a binding in the trait's arguments, `Iterator<Item = &str>` or
`Readable<Storage = UnsyncStorage>`. The name was matched like a bare
type. axum's `impl Iterator<Item = &str>` went to a same-file
`enum Item`, and dioxus's `Storage = …` bindings to the `Storage` trait.
Fix, in isRustNameInScope:
- isRustAssocBinding: a name followed by `=` or `:` inside an unclosed
`<` on its line is a binding or bound, and links nothing. The trait's
own associated type is no node.
- rustQualifiedSelf reads `<T as Trait>::X` (and `<T>::X`) as its self
type and trait, each as the last segment of its path:
- `Self` means `Self::X`: the enclosing impl's own item, nothing in a
trait's body;
- a generic means no impl's;
- a type means its impl of that trait (the candidate's
`Owner::Name` must match, and its impl header's trait too).
Tests: rust-assoc-qualified-self.test.ts, 3 tests, on both engines; all
3 fail before the fix, and switching off either rule fails its tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
6fe9dc1266 |
fix(python): resolve imports from the package roots the project has (#1921)
Python imports now resolve the way the interpreter finds modules: from the package roots the project has, not by any file whose path merely ends in the module's name. A project root is the repository, each service with its own pyproject.toml, setup.cfg or setup.py, its src/, and the package directories its build config declares; a local root answers only importers within its reach, so a test fixture's copy of a package never becomes the application's. Relative imports climb from the importer's own package. Before, `import json` or `from datetime import date` could link to a project file or function of that name, and a src-layout package like flask's was found through a test fixture named flask.py. On flask, fastapi, mealie and django, relative imports now resolve (about 2,200 links added), stdlib and third-party names stop linking to project namesakes (about 1,300 wrong links removed), and imports of a module's function land on the function rather than its file. A sync re-opens what an added or removed module, an edited __init__.py or a changed package root can move. Indexing CPU time is unchanged. Merged with main: a function-local `import a.b as X` (PR 2607) now uses the root-aware lookup, the outside-module receiver check (PR 2606) passes the importer, and plain imports are read at module level only, since the mappings apply to every function of the file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
505c355be3 |
fix(rust): a name written through a path is what the path names, not a same-file namesake (#2711)
A Rust name written through a path is an item of what the path names: a
module (`ast::Pattern`, `io::Error`), a type (`Source::Record { … }`) or a
crate (`mio::Interest`, `std::ffi::OsStr`). isRustNameInScope accepted any
candidate in the file the path is written in, whatever the path said, and
a std path only when the candidate was in another file:
- clap's `std::ffi::OsStr` linked to its own `struct OsStr`, and
`io::Error`, `fmt::Error` and `fmt::Result` in `error/mod.rs` to its own
`Error` and `Result`;
- tokio's `mio::Interest` linked to its own `Interest`, and
`std::time::Instant` to its own `Instant`;
- serde's tests' `Token::Struct { … }` literals linked to their own
`Struct`s, and serde_derive's `syn::Path { … }` to a `Default::Path`
variant;
- gleam's `ast::Pattern` linked to the `enum Pattern` beside it, and
`BinaryBuilderPosition::RecordAttribute { … }` to another enum's
variant of that name.
Fix, in the path branch of isRustNameInScope:
- A path from std, core, alloc or a crate the manifests depend on names
nothing of the project's, in any file, unless the project is that crate
or a `use` in the file binds the root.
- The same-file shortcut is gone. A candidate is the path's when its
file is the path's module, its qualified name holds the segment (a
type's variant or method), or it sits in an inline `mod` of that name
in the file (isInRustInlineModule; rustfmt closes the block at the
indentation it opens at).
- Through a module a `use` binds, a candidate must be in a crate that
`use`'s path can reach (rustUseCanReach, as for a bare name): tokio's
`io::Handle` under `use crate::runtime::io` is tokio's own, not
tokio-test's `io.rs` `Handle` (a dev-dependency).
Tests: rust-path-same-file.test.ts, 6 tests, on both engines; 5 fail
on main (the sixth is the inline-module guard), and the crate-reach one
also fails with only that rule switched off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
5e72a43b3c |
fix(rust): a name a use brings in is the item of the module its path walks (#2702)
tokio's signal/mod.rs writes `use crate::sync::watch::Receiver;` and
tokio-stream `use tokio::sync::watch::Receiver;`, and both linked their
`Receiver<()>` to the `Receiver` of net/unix/pipe.rs. Every `Receiver` in
the crate read as in scope once the file imported one, and the first won.
isRustNameInScope now walks the modules a `use` path names, from the module
the `use` is written in: crate::, self::, super::, a module declared there
(2018 paths), the crate's own name, or a project crate its manifest depends
on. It looks the item up there as Rust does: declared in that module (not
inside a function or an inline module), else brought in by the module's own
`use` of that name, macro-wrapped ones included (tokio's `cfg_sync! { pub use
mutex::{Mutex, ...}; }`), else by its globs. A module declared inline, like
`pub mod futures { ... }`, is found by its braces. A candidate the path does
not name is out of scope, so every strategy, the framework name rule
included, lands on the item the path names.
What the walk can't follow says nothing, and name matching answers as
before: a module with no file, one a path attribute puts elsewhere, a glob
over an enum, a file whose braces don't balance. A module that holds no
such item the index knows, because a macro declares it or another crate
does, leaves nothing in scope. A `use` of the name that yields no item
doesn't hide the globs: clap's `pub use clap_derive::ValueEnum` is a derive
macro, and the trait comes in through `pub use clap_builder::*`.
A/B with fresh indexes, main
|
||
|
|
5a7a4347a6 |
fix(rust): a call on what as_mut() hands back reaches the receiver's declared type (#2710)
A Rust call written x.as_mut().m(..) or x.as_ref().m(..) reaches the resolver by its bare name, so it was matched by name alone. tokio's self.delay.as_mut().reset(now) on a Pin<Box<Sleep>> field linked to the calling Interval::reset, its this.timer.as_mut().as_pin_mut() on an Option to a stream's as_pin_mut, reader.as_mut().poll_read(..) on a generic R to BufReader::poll_read, and dioxus's self.child.as_mut().map(..) and self.server.as_mut().filter(..) on Options to its own GenerationalRefMut::map and Store::filter. Such a call is now read from the call's own chain and resolved on the receiver's declared type as as_mut passes it on: a Pin<P> re-pins what it points at (Rust's lookup through the Pin from the previous change), a Box, NonNull, Rc or Arc lends what it holds, an Option stays an Option, whose methods are std's, unless ? takes the value back out (self.client.as_mut()?.next()), and a type parameter or another std or dependency type gives no project method. A field is read from its struct's declaration, also through pin-project's let me = self.project() (a #[pin] field projects to Pin<&mut T>), even when a pin_project! macro wraps the struct; a local or parameter from its own declaration, which now also reads let x: T = .. annotations. A receiver whose type isn't written where it can be read, a pin! local or a call's result, is left to the name strategies as before. A/B on tokio, axum, clap, serde, ripgrep, gleam and dioxus: 33 wrong links removed, 7 moved to the right method, 13 right links added, none lost, and 28 same-target links now resolved from the declared type instead of by name. axum, clap, serde and the controls express, gin, flask and leveldb are byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
90e2456b43 |
fix(cpp): a bare call on a parameter, local lambda or functor links nothing, not a function elsewhere of its name (#2708)
A C++ call written by its bare name on a name the calling function binds
itself (a parameter, a lambda's parameter, a local lambda or functor, a
range-for variable) calls that local: C++ lookup finds it before any function
or method of that name. The name strategies linked such calls by name:
protocolbuffers/protobuf's code generators' `format(...)` on their
`Formatter& format` parameter went to the conformance suite's
`TestResult::format`, and facebook/rocksdb's tests' local
`auto key = [](int i) {...};` calls to `ArenaWrappedDBIter::key`.
isCppLocalCallableCall, checked in matchReference beside the JS/TS rule,
reads the caller's declarations of the name: its parameters, a declaration
that starts a statement (`auto x = ...`, `T x = ...`, `T x(args)`, a later
name in a list), a range-for variable or a lambda's parameter, the nearest one
in a block still open at the call deciding. A local type or a function the
body declares is not a local callable (the call constructs it or calls the
function), and an expression that reads like a declaration (`a && f(x)`)
declares nothing. A local's type may carry a function type in its template
arguments (`std::function<void()> done, failed;`), so the first name of such
a list counts as the later ones do, and the #2698 test of that list now
expects no edge for either. The looser isCppLocalName used by implicit-this
is unchanged.
A/B on main
|
||
|
|
01cd287786 |
fix(express): only the handler argument decides whether a route is inline (#1957)
An Express route keeps its named handler when a middleware before it
holds an arrow function, like rateLimit({ keyGenerator: (req) => req.ip })
or (req, res, next) => next(). Only the last argument decides whether
the handler is inline, and strings, regex literals and type arguments
no longer end an argument or a body early. The Express, route and
framework suites pass (757 tests); on express itself three named
handlers gain their link.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
9dc3bc3adc |
fix(resolution): honour TypeScript type modifiers on imports and re-exports (#1955)
Import and re-export lists are now read with TypeScript's `type`
modifiers (`export type { A } from`, `export { type A } from`,
`export type * from`), comments inside the list, ES2022 string names
and JSDoc @import tags. A type re-exported from a package, like vben's
`export type { VxeGridProps } from 'vxe-table'`, no longer links to a
project type of the same name, and type imports link through the
import rather than by name. The import-related suites pass (609 tests)
and indexing CPU time on vben is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
63476df6a6 |
fix(react): JSX at module scope, in a top-level const or in a test callback renders from where its calls are attributed (#2611)
JSX outside every function now renders from what a plain call there is attributed to: a top-level value, or the file. Ownership is by line, so no tag counts twice. Merged with main's destructuring rules (PRs 2676 and 2677): an owning parent takes a name as its local by its own lines or by the file's top-level destructuring, and function parents keep main's scope rules. The viewer's shared-chrome count no longer counts a file as a render parent. A/B: excalidraw +132 and bulletproof-react +38 render sites (tests to the components they render, entries to their root apps, stories to their components), none removed. Fixes issue 2587. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e3f23cc4bc |
fix(go): a local's scope ends at its case clause, and a func-typed result's parameters are not locals (#2597)
Main's gate for a Go call to a local func value or parameter that shadows a package function (PR 2658) reads scopes through the Go scope reader, and two of its readings were too wide. A name declared in one case of a switch or select stayed in scope in the clauses after it, and the parameter names inside a func-typed result, like func() func(run string), *func(...) or chan<- func(...), were read as the function's own. Either made a later call to the package function look shadowed and drop its link. The PR's own earlier shadowing check is left out: the gate already covers every case its tests pin. Go A/B on gin, cobra, etcd, prometheus and hugo is byte-identical. Fixes issue 2580. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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
|
||
|
|
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> |
||
|
|
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>
|
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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
|
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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>
|
||
|
|
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>
|
||
|
|
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> |
||
|
|
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
|
||
|
|
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
|
||
|
|
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
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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>
|
||
|
|
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>
|
||
|
|
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> |
||
|
|
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
|