A method that delegates to another overload of itself -
`toInstant(instant)` returning `toInstant(instant, Instant.EPOCH)`,
`DeserializeXNode(value)` returning `DeserializeXNode(value, null)` - bound to
itself, since every overload shares the name: the fuller overload never
listed its convenience overloads among its callers, and its impact missed
them.
When a name match lands on the calling method itself, in a language that
overloads by arity (C#, Java, Kotlin, Swift, C++, Scala, Dart, VB.NET), the
call's argument count is read and compared with the method's parameters
(defaults and varargs / `params` / `...` counted); if they cannot take it,
the one same-owner overload they fit is the target. Real recursion
(`depth(n - 1)`) keeps its self-edge.
Self-loops -> overload edges: commons-lang 637 -> 457, Newtonsoft 303 -> 196,
halo 173 -> 116, okhttp 248 -> 208, Alamofire 147 -> 120, gson 74 -> 55,
AutoMapper 71 -> 57 (edge counts unchanged; overloads share a qualified
name, so only the target moves).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The React resolver's `languages` gates its route extraction, not its
resolve(): framework resolvers see every language's references. Its
component rule was already JSX-only, but its hook (`use...`) and context
(`...Context` / `...Provider`) rules were not: in halo - a Spring app whose
UI package makes React detected - 209 Java import edges (`SecurityContext`,
`ApplicationContext`, `ObjectProvider`, `DirtiesContext`...) were resolved by
it onto import nodes. It now answers only JavaScript / TypeScript / TSX /
JSX references.
halo -209 +3 (a Java test's `responseContext()` helper now resolves to
itself); trpc, excalidraw, react-redux-realworld, bulletproof-react,
react-native-reusables unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Framework resolvers see every reference of every language, and the Vue
resolver had no language guard: its PascalCase-component rule took
mealie's Python `QueryFilterBuilder(...)` (an unresolved import) to the
`QueryFilterBuilder.vue` component at 0.8, and its macro / auto-import rules
matched any language's `ref(...)` or `computed(...)`. It now answers only
refs from vue / javascript / typescript / tsx / jsx files.
mealie: 6 Python calls reroute to the Python class; halo, elk, element-plus
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A test suite is not linked into the program, so a name match from
production code into one is coincidence - but only Strategy 3's receiver
guess (#2171) ruled it out. Now no strategy's name match reaches a symbol
in a test suite from a non-test file: a test source set (`src/test/`,
`jvmTest/`), a `tests/` / `__tests__/` / `spec/` / `e2e/` directory, a
`FooTest.kt` / `test_foo.py` / `foo.test.ts` / `foo_spec.rb` file.
Test-support code a project ships - `testing/`, `fakes/`, `mocks/`, a
`*-test` module - stays in reach, and `…Spec.java` (halo's `IndexSpecs`,
okhttp's `ConnectionSpec`), `post-spec.ts` models and `useTests.ts` hooks
are not test suites.
typeorm -64 (`Record<K, V>` -> a test entity), okhttp -164 (117 sample
`@Override` -> a test's nested `Override`), kotlinx.coroutines -318
(`import kotlinx.coroutines.*` onto one test file's package node), sttp -62,
Exposed -92, halo 0, element-plus -36 (`isClient` -> a test's vueuse mock),
excalidraw -10 (`actionManager.executeAction` -> the test `API` helper),
tokio -30, trpc -36, AutoMapper -37, netbox -22, cats -21, mealie -10,
pytest -8, Alamofire -7; zod, eShop, react-native-reusables unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`answers in under 100 ms` took one wall-clock sample while the rest of the
suite ran in parallel, and failed under that load at 250-430 ms (three
times in one day of full-suite runs) while passing alone. It now takes the
fastest of five warm requests: contention is gone from at least one, and a
real slowdown is slow on every one.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Dart joins Rust/Go/Kotlin/C# with a standard-method list (String, List,
Iterable, Map, Set: endsWith, contains, forEach, putIfAbsent, where,
sublist...): a guess onto a project method of such a name needs a receiver
named after its owner. And a Dart extension's owner, for that naming, is the
type it is `on` - getx's `ext.endsWith(".avi")` on a String shared the word
`Ext` with `extension RxStringExt on Rx<String>`, none with `Rx<String>`.
getx -36 (`RxStringExt::endsWith` x23, IOHttpResponse::join/toList),
riverpod -37 (`UnmodifiableMap::putIfAbsent/addAll` on plain maps), bloc -18
(`ignore.contains(...)` -> GithubCache, a Map's `forEach` -> _Emitter; bloc's
untyped `emit.forEach(...)` handler lambdas lose their lucky guess too).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#2172 made the members of every type a project function type takes as a
receiver reachable from any bare call, since it could not tell which
lambda a call is in. With several such types in reach, proximity chose:
koin's `single { C51(get(), get()) }` and `Scope.new(...)`'s `get()` went to
`Koin.get` (koin also has `Koin.() -> ...` lambdas), 2,190 times.
- A lambda's receiver is read from the function it is passed to: the type
before `.(` in its last parameter's function type, directly or through a
typealias (`definition: Definition<T>`, `typealias Definition<T> =
Scope.(ParametersHolder) -> T`), when every project function of that name
agrees. The brace frames put it in the lambda's hierarchy.
- Of the members a bare call can reach, those its lexical hierarchy reaches -
its class, an extension's receiver, the lambda it is in - come before those
only the project-wide receiver set reaches.
koin: `get()` -> Scope (2,184), `viewModel` in `scope { }` -> ScopeDSL,
`modules(...)` in `startKoin { }` -> KoinApplication. Exposed: `varchar(...)`,
`integer`, `reference`, `datetime` in a table object -> Table's (were a
test table's same-named property). kotlinx.coroutines: `launch { }` ->
CoroutineScope.launch (was a test DSL's). Edge counts ~unchanged (targets
move): koin, Exposed, okhttp, coroutines, okio; nowinandroid, moshi
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The declared-member receiver inference #2171 gave C#, Java and Kotlin now
reads Swift too: `var cache: ImageCache!`, `let storage: DiskStorage.Backend<Data>`,
`self.x` as well as `x`, a function's own `let` shadowing the property. The
dotted-call path types the receiver from it, and a chained bare call keeps
only members of that type or its supertypes / protocols.
Kingfisher: `cache.imageCachedType(forKey:)` -> ImageCache's (was a test
subclass's override), `storage.store/value/isCached` -> DiskStorage.Backend,
`manager.retrieveImage` -> KingfisherManager (was a test double), DispatchQueue
`ioQueue.async` no longer a project method. realm-swift: `List::append`,
`RealmCollection::sum/index` (were Objective-C RLMArray selectors); vapor:
`self.storage.write` -> NIOHTTPBodyWriterStorage.
Kingfisher -100 +179, realm-swift -108 +203, Alamofire -16 +54, vapor -15
+10, IceCubesApp -6 +5; Newtonsoft.Json, okhttp unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A vendored minified script (`*.min.js`, or a script of a few enormous lines
- the same detection #2122 uses to rank them last) keeps mangled one-letter
names, so a name match from any other file is coincidence: healthchecks'
369 `$(...)` jQuery calls went to a helper inside bootstrap-native.min.js,
TestBox's popper.min.js to jquery.min.js internals, flaskbb's docs script
to its vendors bundle. Such files' symbols are no longer visible across
files by name; calls inside a bundle still resolve.
healthchecks -460, flaskbb -48, TestBox -36; bat, lodash, minimal-mistakes,
netbox, express, excalidraw unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A chained Swift call accepted any same-named member unless its name was a
standard-library one: vapor's `JSONDecoder().decode(...)` and even its own
`URLQueryDecoder().decode(...)` went to `ClientRequest._URLQueryContainer
.decode`, IceCubes' `JSONEncoder().encode(self)` to a filter's `encode`,
realm's `Realm().create(...)` to a test object's `create`.
When the link before the call is a constructor - `TypeName(...)` with flat
arguments - the member must belong to that type or a supertype / protocol
the project gives it; an outside type (JSONDecoder) keeps only the
project's extensions of it. A capitalized C function
(`RLMObjectBaseObjectSchema(obj)!`) constructs nothing and is left alone.
vapor -63 +62 (`URLQueryDecoder::decode`, `URLEncodedFormParser::parse`),
IceCubesApp -23 +1, realm-swift -19 +19 (`Realm::create`), Alamofire -1;
Kingfisher unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- A bare Lua call cannot reach a table's method (`function M.x`,
`function M:x`) without its table: kong's 118 `error(...)` calls went to
its response PDK's `_RESPONSE.error`, 111 to a mock's `error`, busted's
`setup`/`teardown` to perf helpers' and factories'.
- A bare call to a Lua global (`ipairs`, `error`, `require`, busted's
`describe`/`it`/`setup`...) is Lua's unless the file defines its own
function of that name: telescope's 120 `for _, v in ipairs(...)` went to a
linked list's `ipairs` method, apisix's 36 `require(...)` to a wasm
module's `_M.require`.
- A function's own locals are not nodes, so the alias reader now reads
`local x = ...` from source above the call within its function, and a
member of a host global table (`kong.request.get_query`) resolves to the
one method of a table named after its holder (`_REQUEST`). kong's
`local clear_header = kong.service.request.clear_header` had resolved to
the RESPONSE module's - now nothing, correctly.
telescope -129, kong -516 +58 (indexing 4.7s -> 3.5s), apisix -57 +18,
lua-resty-core -4, roact -3 +1.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`fmt::format("{}", x)` resolves through the macro-namespace matcher
(#2176), which took the first same-named function of the namespace -
color.h's `format(const text_style&, format_string, T&&...)` - for all of
fmt's 1,400 `fmt::format` calls, and likewise `print`, `format_to`,
`vformat`.
Among an overload set the call's arguments are now read (to a dozen lines)
and each overload's parameter list from source (C++ signatures are empty):
an argument count outside the parameters' is out; a string-literal argument
fits a parameter that names a string type best, a template parameter
(`const S&`) less, anything else not; a narrow literal never fits a wide
parameter (`wformat_string`, `wstring_view`) nor a wide one a narrow one.
`...` inside `format_string<T...>` is not a pack.
fmt: `format` -> format.h (1,363) and xchar.h for `L"..."` (57),
`format_to`/`print` -> core.h, `vformat` -> format-inl.h; spdlog's bundled
fmt the same; pybind11's `py::set()` -> pytypes.h's `set` class. json,
rapidjson, leveldb unchanged. Edge counts unchanged (targets only).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Express-style route extractor attributed an inline arrow handler's calls
to the route by bare name - `c.text('Hello')` became `text` - so each
matched whatever same-named symbol the project had: hono's 419 `c.text(...)`
routes called its client's `ClientResponse.text`, `c.html(...)` its `html`
helper, `c.req.parseBody()` a utility `parseBody`. A member call now keeps
its receiver (`c.text`, `userService.lookup`) and resolves like any member
call; a member of an expression (`a.b().c(`) names nothing to follow. Both
the plain and the `router.route(...).get(...)` forms share the scanner.
hono -538 +71 (`Context::text` / `Context::html` where the receiver
resolves; `c.req.*` 3-link chains now stay unresolved like any other
untyped chain); express, react-redux-realworld, trpc, kit, BookStack
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A later link of a Scala chain (`arbitrary[Int].map { ... }`) accepted any
type or object candidate: alleycats' `object map`, cats' `instances.map`,
`syntax.flatMap` and `show` objects took 418 such calls. A type or object is
now a chain link only when the receiver names what holds it - its outer type,
or for a top-level one its file's package (Scala qualified names leave the
package out): `sttp.client4.Response(...)`, `fs2.concurrent.Topic(1)`.
cats -418, sttp -5 (akka's `FormData.BodyPart`, a Java `_.stream()`), fs2
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A bare Python call whose name the enclosing function binds - an assignment
(`view = SomeView.as_view()`, tuple and annotated forms), a parameter, a
`for` / `with ... as` / `except ... as` target - or the module binds at top
level, no longer resolves to a same-named function in another file. DRF's
tests write `view = X.as_view()` then `view(request)`: 118 such calls went
to one test file's `def view`. Read from code only (docstrings and comments
blanked), and an imported name is left to the import. A pytest fixture
(`@pytest.fixture`, or anything in a conftest.py) is still what a test's
parameter of that name calls.
django-rest-framework -122, pytest -25 (`func` / `xfail` params and
aliases), allauth -12 (`serialize_instance = get_adapter().serialize_instance`),
netbox -6 (migrations' `apps.get_model(...)`), mealie -3, flask -2;
healthchecks, flaskbb, httpx unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Strategy 3's scoring already skipped a test double (`Mock…`, `Fake…`,
`Stub…`, `Dummy…`, `Spy…`) the receiver and the calling file never name
(#2175), but the unique-method shortcut before it did not: django-allauth's
`resp.json()` on a Django test-client response went to `MockedResponse.json`
193 times, as the project's one `json`. The shortcut now applies the same
rule.
django-allauth -193, pytest -15 (`MockTiming`), mealie -8 (`FakeSession`,
`_FakePostClient`); netbox, healthchecks, typeorm, eShop, BookStack
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The JVM import reader required a `;`, so a Kotlin file had no import
mappings at all. It now reads `import a.b.C` and `import a.b.C as D`.
- The outside-import rule from #2195 applies to Kotlin: `import
java.net.Proxy`, `import org.mockito.Mockito.mock`, `import okio.buffer`
own their names. A declaration the file itself makes comes first, in its
own namespace (a callable for a call, a type otherwise) - Exposed's
`toLocalDateTime(value)` beside `import kotlinx.datetime.toLocalDateTime`
is the column type's member; gson's `new URI(...)` stays `java.net.URI`
beside `TypeAdapters`' field `URI`.
- The mappings pick among same-named project classes: okhttp's
`MockResponse.Builder()` (642) and `Request.Builder()` reach their classes,
Exposed's `TestDB`/`SchemaUtils` the module the file imports, moshi's
`Moshi.Builder()` (102).
- A renaming import binds its alias by FQN: kotlinx.coroutines' `import
...internal.unsafeFlow as flow` makes its 28 `flow { }` builders
`unsafeFlow`, not the public `flow`.
okhttp -486 +1303, Exposed -1685 +1351 (duplicate-module reroutes; losses
are kotlin.test/kotlinx/okio/clikt/Gradle functions), moshi -21 +121, okio
-128 +51, koin -22 +11, coroutines -68 +47, nowinandroid -44 (Gradle DSL,
Compose). Java repos (gson, commons-lang, retrofit, jsoup, halo)
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A single-type or static import (`import java.lang.reflect.Field;`,
`import static org.mockito.Mockito.verify;`) whose package prefix is none of
the project's JVM packages now makes that name mean the outside class: no
reference, call or instantiation resolves it to a same-named project symbol.
Imports of the project's own classes - nested ones included - resolve as
before, since their package prefix is a project package.
Wrong edges removed: gson's production code -> a test's nested
`ParameterizedTypesTest.Field` (42), jsoup's W3C converter -> jsoup's own
`Document`/`Element`/`Node` (51, it imports org.w3c.dom), retrofit's
`java.lang.reflect.Type` -> a test class `Type` (204) and `org.junit.Rule` ->
test rules, commons-lang `IOException` -> a test's nested exception (233),
halo's Mockito `verify(...)` -> a code store's `verify`, and
`new TemplateEngine()` -> an application.yaml key.
gson -60, commons-lang -389, jsoup -51, retrofit -466, halo -83, mall
unchanged; no edges gained.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A Java enum constant or Kotlin enum entry with a class body -
`PLUS { int apply(...) { ... } }`, `NewBuffer { override fun pipe() ... }` - was
recorded as a bare enum_member: its body was never visited, so its methods
were missing and every call in them was dropped. jsoup's tokenizer
(`TokeniserState`, one `read` per state) and tree builder
(`HtmlTreeBuilderState`) are written this way.
The body is now visited under the member (QN `Op::PLUS::apply`), which
counts as class-like so its functions are methods and its properties fields.
Only a `class_body` child is visited, so Rust's struct-like variants (a
`body` field of field declarations) are untouched. Mirrored in the kernel's
Java and Kotlin walkers; kernel parity is byte-identical on the fixtures
(Torture.java gains a constant-with-body enum; torture.kt already had one)
and on gson/koin/okio.
jsoup +2156 edges, okio +138 -23, okhttp +106 -11, gson +97, halo +29,
commons-lang +16; koin, Exposed, mall unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- A `val` the graph files under a class but that is written inside a block
of its body (cats' `test("…") { val f = … }`) is that block's alone. It
took `f(…)` calls from lambda parameters in other suites and from cats'
core library (`FreeT::FlatMapped::f` from option.scala, Invariant.scala…).
A `val`/`const` declared inside a function's lines is likewise local
(outside C/C++, whose nesting is not trusted; a Lua global stays global).
- In a class body with no enclosing method, a binder (a lambda parameter, a
`val`) counts as local only inside a block still open at the site.
- Only an import rooted at a value (`import builder._`) lets any type's
members in; a lowercase package path (`import cats.syntax.all._`) did too.
- An imported object's supertypes are in scope, and `package object x
extends Api` (no node in the graph) is read from source - imported, or the
file's own package: sttp's `multipart(...)`, `asJson(...)`, `asEither(...)`.
cats -478 +63, sttp -153 +81 (sampled losses: other tests' locals, scalatest
`test`/`eventually`, libc `free`, `sttp.model.Header`). fs2, http4s, okio,
koin, Exposed, lodash, excalidraw, flask, kong, jekyll, halo unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`export * as core from '../core/index.js'` was recorded as a plain wildcard,
so a barrel walk for `z.number()` went into core, on through core's own
`export * as regexes`, and landed on the `number` regex constant - ahead of
the `export * from './schemas.js'` that holds the schema function. zod's
`z.string()` (262 calls), `z.number()` (141), `z.email()`, `z.boolean()`...
all went to regex constants.
- A namespace re-export is now its own kind: it supplies only `ns`, and a
member path through it (`z.coerce.number()`, `z.core.safeParse()`)
continues in that module. A 3-segment chain is resolved when its root is an
`import * as` binding and only through the import resolver - untyped chains
stay unresolved as before.
- A named re-export (`export { safeParse } from '../core'`) is found for a
namespace import's member; the walk compared against `'*'` and only reached
those through the misread wildcard.
zod -471 +571 (every regex-constant edge now reaches the schema function;
`z.lt` -> core `_lt`, `z.coerce.string` -> coerce.ts), trpc +4 and kit +1
(namespace-import members through named re-exports). typeorm, hono,
excalidraw, element-plus, starlight unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Four gaps left CommonJS calls on the local alias variable - or on the wrong
function:
- `require('../')` up to the project root produced an empty relative path, so
its `/index.js` candidate was never found;
- a default import never followed `module.exports = X` /
`exports = module.exports = X` / `module.exports = require('./lib/x')`;
- only the first declarator of `var a = require('x'), b = require('y')` was a
binding, so `b()` - a package call - stayed on the local variable;
- `require('./utils').member` was read as the module's DEFAULT export: every
such alias in express resolved to utils' first exported function
(`normalizeType`). It is now the named member, and `exports.name =
function impl(...)`, `module.exports.name = impl` and `module.exports = { a,
b: c }` bind names the export index could not see.
express -1087 +727 (707 `express()` calls reach createApplication; supertest /
node:assert calls no longer edge to the local variable), eslint -750 +827
(`new RuleTester()` reaches the class, not another test's variable), mocha
-83 +90 (`run(...)` no longer lands in another spec file), koa 65 wrong
`request` edges -> `response`, body-parser +20. zod, trpc, hono, typeorm,
axios unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Kong (and OpenResty code generally) localizes everything it calls:
`local splitn = require("kong.tools.string").splitn`, `local check_phase =
phase_checker.check`, `local fmt = string.format`, `local type = type`. Every
bare call then resolved to the same-file alias variable - 8,000 edges on kong,
more than its calls into functions - a dead end for the real callee.
A bare Lua call whose name is a `local` alias in scope is now followed:
- `require "m"` (or a require-named loader like kong's `reload_module`) plus
members, or a member of such a local, goes to the module's function of that
name, or to what the module exports under it (`return { check = check_phase }`,
`unindent = misc.unindent`, up to three hops);
- an alias of a Lua global or standard-library table is no edge, unless the
project patches that function itself outside its tests (kong's `ngx.sleep`);
- a module outside the repo is no edge;
- anything else resolves as before.
A `local` reached this way is visible across files.
kong: -7057 +1150 (every loss is a std/outside alias or a reroute), indexing
4.3s -> 3.3s. apisix -3507 +170, lua-resty-core -967 +231, telescope -28 +17
(all reroutes or outside modules), lazy.nvim reroute only, roact unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
bulletproof-react writes every link as `<Link to={paths.app.discussion.getHref(id)}>`
and every redirect as `navigate(paths.auth.login.getHref(...))`, so none of its
navigation reached a route. The href reader now follows the config object to
where it is declared (through imports and tsconfig aliases), takes the string or
template the helper returns, keeps a whole-segment `${id}` as a parameter and
drops a hole glued onto a segment (a `?redirectTo=` suffix).
The Link tag pattern also stopped at the `>` of an arrow attribute written
before `to` (`onMouseEnter={() => prefetch(id)}`), which hid those links.
bulletproof-react: 0 -> 11 navigates edges; jira_clone, ecommerce-react,
react-redux-realworld, create-t3-turbo and excalidraw unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
nlohmann/json's basic_json was lost whole. Offset-preserving preParse
fixes (the kernel parses the same text):
- an access specifier spelled as a macro (JSON_PRIVATE_UNLESS_TESTED:,
Q_SIGNALS:) becomes the keyword it stands for, padded
- a lone attribute macro is blanked after a comment line (/// @sa
https://…/meta/ ends in '/') and after a template head (ends in '>'),
which read as operator continuations; a line's continuation is judged
on its code, so 'CURLE_X, /* 100 */' still continues (curl's enums)
- a preprocessor conditional where the code before it hasn't ended a
statement/declaration (in an initializer list, between a template head
and its function, in an argument list) keeps its first branch:
directives and later branches blanked; #define continuation lines and
statement macros without ';' (RAPIDJSON_DIAG_OFF(x)) are not code
Parse-error files: redis 192->186, curl 210->203, pybind11 98->95,
spdlog 111->110, leveldb 21->20, none newly broken across json, rapidjson,
fmt, jq; kernel parity 0 diffs; basic_json 0 -> 393 members.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The local-only check against this repo's own index asserted LRUCache.get
has 500+ callers; sharper resolution (calls on maps and caches that were
never LRUCache's no longer link to it) brought it to 496 and the test
failed on every machine with a local index. What it checks is that the
hub's list is capped and grouped, so require more callers than the
300-row cap instead.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
tree-sitter-kotlin 0.3.8 predates `when` guards (2.1), `..<` (1.9),
multi-dollar strings (2.1) and nullable function-type receivers; each
made error recovery drop the class around it (Exposed's dialect and
query classes came out as loose functions).
Offset-preserving preParse rewrites (so the kernel parses the same text):
`is X if cond ->` -> `is X, cond ->` (the condition stops short of
`->`, so `is X -> if (…)` bodies are untouched), `..<` -> `.. `, the
`94189` prefix blanked, `T?.() ->` -> `T.( ) ->`. Parse-error files:
Exposed 65 -> 43, kotlinx.coroutines 50 -> 46; koin/okhttp/moshi/
nowinandroid/okio unchanged, none newly broken; kernel parity 0 diffs.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Member-type inference rescanned the whole class body — method bodies
included — once per distinct receiver name, and rebuilt the calling
method's body text for the shadow check on every ref; the inherited-
class-method walk re-read heads per ref. On Exposed (huge test classes)
methodCall misses cost ~3x the pre-#2171 time.
- a class's member-level lines (brace depth <= 1, comments/strings
dropped) are collected once and each name only regexes those
- the supertype walk and the shadow check (now over the whole calling
function) are memoized per (class|function, name)
- declared supertypes and inherited class methods are memoized
Edges unchanged on Newtonsoft/eShop/gson/Exposed/koin/horse/DRF (±2 on
AutoMapper/commons-lang/okio from the whole-body shadow check); Exposed
index 8.5s -> 7.7s, Newtonsoft 3.6s -> 3.3s.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Strategy 1 (a receiver naming a class) looked only in the class's own
file, so an inherited class method fell to the name-word guess: Horse's
THorse.Get('/ping', …) (THorseCore's, three class(…) heads up) went to a
route-group interface's Get 120 times.
When the class itself declares no such method, walk the supertypes its
declaration heads name (Pascal class(…), Python bases, Ruby <, PHP/TS/JS
extends, and the existing Java-family / Dart / Swift / ObjC / Scala
readers), nearest first, up to five levels.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`[super init]` was judged like a self-send, so the sending class's own
override passed (SDDiskCache's [super init] came back to itself), and
where tree-sitter-objc lost an @implementation's range no hierarchy was
read at all, so any class's init passed (NSObject subclasses' [super
init] -> SDDiskCache::init).
- a super-send excludes the class it is written in
- a lost @implementation's class is read from the enclosing method's
qualified name (SDWebImageDownloaderDecryptor::initWithBlock:)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Solidity: a receiver-less call reaches a function of the contract
around it or one it inherits (heads read from source, `is` clause with
constructor args dropped); OpenZeppelin's _msgSender() in Context-based
contracts went to ERC2771Context's override 83 times.
- Erlang: another module's function is called bare only through
-import(Mod, [f/N]) (or from an included .hrl): cowboy's
-import(req_SUITE, [do_get/3]) went to compress_SUITE's do_get/3; with
no import, no cross-module guess.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Rust: a CamelCase path receiver the project doesn't declare (Vec::new,
String::from, Default::default — not Self, not a SCREAMING static) is
an outside type; a lowercase module path (task::spawn, io::stdout)
never reaches a method. tokio: task::spawn -> TaskTracker::spawn x300.
- Rust/Go: a chain link on a later line (bat()\n.stdout(…)) is chained,
named after the chain's head; std::process / assert_cmd pipe and
assertion names join the Rust std list.
- Go: w.Header().Get/Set/… is net/http's Header.
- R: a plain call never reaches an object's method (base range(x) went
to a ggproto Coord's range) — exact and fuzzy paths.
- JS: fetch body methods (text/json/arrayBuffer/blob/formData) are
builtins.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
fmt opens its namespace with FMT_BEGIN_NAMESPACE, pybind11 with
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE), rapidjson/spdlog with
…_NAMESPACE_BEGIN — the extractor sees a bare macro line, so every
declaration inside is indexed without its namespace and fmt::format(…)
(1,728 calls on fmt) resolved to nothing.
As a last resort for a qualified C/C++ name, read the project's
namespace macros (object-like and single-parameter function-like
openers, through identifier aliases, inline namespaces transparent;
closers by brace count), the ranges each opens per file, and namespace
aliases (namespace py = pybind11;), and match the declaration whose
macro prefix + qualified name is the name called. fmt +2480, pybind11
+1446, spdlog +264; tokio/serde/gin/excalidraw/Newtonsoft unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The receiver-word guess picked framework-dispatched handlers and test
doubles by a single shared word: django-allauth's test client.post(…)
landed on a ClientRegistrationView's post 425 times, mealie's
response.json() on a test's _FakeHTTPResponse 424 times.
- view / viewset / controller / endpoint (and view-mixin) HTTP-verb and
CRUD-action methods are ruled out of the guess (and the ruling-out can't
leave a lone guess behind — narrowed)
- a Fake/Mock/Stub/Dummy/Spy owner is guessed only from a file that names
it or a receiver named like a double
- Python: `x = Model.objects.create|get|first|last|latest|earliest(…)`
types x as Model (Django manager calls), so x.save() reaches the model
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`Users.id eq id1`, `single { … } bind I::class`: an infix_expression was
never extracted, so a project's infix DSL had no callers (Exposed's
`eq` > 1,000). Extract it as a call of the middle simple_identifier —
`lhs.fn` when the left operand is a plain name, else bare — in the TS
walker and the kernel (kernel-parity 0 diffs on okio/okhttp/Exposed).
A standard infix name on an expression receiver is gated like a chain
link (`alias(x) apply false` in a build script); a project's bitwise
extension on a number type (okio's `Byte.and`) is never chosen, typed or
guessed, since the stdlib's Int/Long members take `x and 0xff`.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
tree-sitter-kotlin 0.3.8's external scanner inserted an automatic
semicolon on the same line before any word starting with `e` other than
`else`, so Exposed's `Users.id eq id1` ended its statement early and
error recovery could swallow the class around it (r2dbc UpsertTests
became one loose function nesting every test).
Patch scanner.c (same line: never a semicolon before an e-word) in both
the vendored kernel C and the wasm build; provenance, shas and rebuild
recipe in docs/grammars/tree-sitter-kotlin.md. Exposed files with a parse
error 229 -> 71 of 1,004; koin, nowinandroid, moshi, okio, okhttp and
kotlinx.coroutines unchanged (one okhttp file fixed, none broken);
kernel-parity 0 diffs.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A receiver-less Kotlin call exact-matched any class's same-named method:
koin's module { } in one test went to another test class's private
module 268 times, error("…") to a Logger's error, get() inside a
definition lambda to Koin's get rather than the Scope it runs on.
A bare call now reaches a method of a class, anonymous object or extension
receiver around it (read from nodes and from the source's braces, so a
class the parser lost still counts) and what those inherit (with Android
framework ancestry), of a type the project's function types take as a
lambda receiver (plus outside types it writes extensions on), or of an
object the file imports. with/apply/run blocks and .kts scripts are left
unjudged; Kotlin's require/check/assert preconditions are the stdlib's.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
C# / Java / Kotlin receivers that are fields, properties or parameters were
typed only when declared in the calling method without generics, so a call
through a field fell to the receiver-word guess: Newtonsoft's
_innerWriter.WriteValue() landed on the wrapper's own WriteValue, a
TextWriter's Write() on a test writer's, commons-lang's DateFormat field's
parse() on DateParser 284 times.
- read class-level member declarations (brace depth 1, comments skipped),
walking base classes with their type arguments substituted, C# using
aliases, type-parameter bounds, generic and for-each declarations
- C# interface members default public and namespace-level types internal
(TS extractor + kernel, parity 0 diffs); interface calls resolve at all
- the receiver-word guess weighs the owner type's name only, the receiver's
last link (a constant's type), and its head noun; .NET std names need a
receiver named after the owner; production code never lands in a test
suite's mock
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Swift's extractor keeps one receiver level, so super.init(…), a longer
chain's removeAll() and a bare min(a, b) all arrive as bare names and
exact-matched whichever project member shared the name. A bare or self./
super. call now reaches only a member of the types around it and what they
inherit or conform to (source-read heads, UIKit ancestry, the standard
collection protocols), nearest first; a standard-named chain link needs a
receiver that names the owner, an outside owner, or an argument label only
the project's method takes; playground and test-target globals stay put.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
When a receiver's type is inferred from its declaration or initializer and
the method isn't on it, the matcher used to fall through to its
capitalized-name and name-overlap guesses. If the inferred name is a type
(capitalized last segment) that nothing in the project declares — JDK /
BCL / okhttp / Django types — it now stops: the method is that outside
type's. Python's initializer pattern no longer reads a keyword argument
(`prefix=IPNetwork(…),` inside a call) as a binding of `prefix`.
A/B (edges removed): commons-lang -1296 (`append` / `length` / `charAt` on
JDK types), Newtonsoft.Json -496 (`MemoryStream.ToArray`, `ToString`),
gson -367 (`List.add`, `Map.put`), retrofit -321 (okhttp `Request.headers()`
/ `method()`), jsoup -130, okio -26, pytest -44 (pathlib / io), netbox -25,
healthchecks -9 (`TimestampSigner.sign`), flask -9, zod -1.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- tree-sitter-kotlin can't read `class Name` / (comments) / `internal
constructor(…) : Super {` on separate lines — the class is dropped and its
members become loose top-level functions (okio's ByteString, Kotlin
Multiplatform's `expect` classes). The Kotlin preParse now blanks that
constructor's modifiers / annotations / keyword to spaces, so `(…) :
Super {` parses as the primary constructor; offsets and lines survive, and
preParse runs before the kernel, so both paths parse the same bytes.
- With members back on their classes, a Kotlin standard-library name on an
untyped chain link (scope functions, collection / string / conversion
methods — not names project types commonly carry) needs a receiver named
after its owner, in the exact / fuzzy filters and the unique-name guess.
A/B (edges removed / added): okio -1028/+1127, okhttp -979/+1145,
kotlinx-datetime -426/+515 (mostly re-keyed onto recovered classes),
koin -60/+4 (`msg.contains(…)` → a dependency map's `contains`).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The extractors keep one receiver level, so chain links arrive as bare names.
Read at the call site:
- bare (no `.` / `::` before it): never a method — Rust reaches one only
through `self.` / `Type::`, Go through a receiver (axum's routing
`get(handler)` went to a cookie jar's `get`, tokio's `drop(x)` to `Drop`
impls, #1861's pinned `reset()` → `Target::reset` is now the free fn);
- chained (after `.`, receiver read back through arguments, macros `name!`,
`::` paths and Go composite literals): never a free function, and a
standard-library method name (Option/Result/iterator/collection/string
methods; Go's String/Error/Header/locks/reflect/time) needs a receiver
named after its owner — project-specific names keep their match (clap's
`flag("n").short('n')` → Arg::short, cobra's `c.Root().Name()`, gin's
`c.Set(…)`).
The same std gate applies to the method-call matcher's unique-name guess.
A/B (edges removed / added): clap -1496/+93, tokio -1064/+235, axum
-695/+42, ripgrep -477/+32, cobra -167, serde -119/+1, bat -40/+4, gin
-32/+26.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`Name.method()` where `Name` reads as a type in the language's conventions
and nothing in the project (same language family) is called `Name` — JDK /
BCL / DOM / Indy types — now leaves the method-call matcher before the
capitalized-receiver and name-overlap guesses. Not applied in Go (exported
package variables), C / C++ / Rust / CUDA / Metal; in Pascal only Delphi
type prefixes (T/E/I…) and `Exception` count, since parameters and locals
are capitalized there too.
A/B (edges removed): commons-lang -1636 (`Integer.valueOf` → StringUtils
×804, `Calendar.getInstance`, `Instant.now`), horse -89 (`Exception.Create`
→ EHorseException), retrofit -79 (OkHttp `RequestBody.create` / `HttpUrl.get`),
typeorm -74 (`Object.assign` → ObjectUtils), gson -100, zod -63,
Newtonsoft.Json -57, jsoup -18; gin and cobra byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Route tables compose nested paths: a child's `path` is relative to the
path-bearing routes around it (`children` of a data router, nested
`<Route>` elements), absolute ones reset. `lazy: () => import('./x')`
(object and JSX) renders the module's default export (`Component` export
as fallback) via a claimed `lazy-import:` ref. `path: paths.app.root.path`
keeps its parts on the node's signature and is named in postExtract from
the constant's object literal (found through the file's import). The
route keeps its extracted id; `isReactRouterRoute` accepts it. An element
wrapped in parentheses or a guard (`<ProtectedRoute>`, `<Suspense>`,
`*Provider`, `*Guard`) renders the first element inside.
- Import aliases: the tsconfig / jsconfig nearest the importing file that
declares `paths` is tried before the root's, so each monorepo app resolves
its own `@/*` / `~/*`.
A/B (edges removed / added): bulletproof-react -43/+367 (0 → 9 named,
linked routes; cross-app imports fixed), react-native-reusables -103/+193,
kit -184/+218, trpc -45/+71 (examples' `~/…` now their own), create-t3-turbo
-1/+13; excalidraw, halo, obytes, realworld byte-identical. #1348's nested
fixtures now expect composed paths (`/dashboard/settings`, `/data/prefs`).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
`const { getDefaultActivityRoute } = useDefaultActivity(); getDefaultActivityRoute()`
bound the name locally, which ruled out every cross-file candidate, so the
call resolved to nothing. A bare JS-family call through a name destructured
(`{ key: alias }` included) from a call's result now resolves the callee —
through the file's imports, else the same file, else the project's one
function of that name (Nuxt's `~/` alias) — checks its source returns the
key, and takes the function declared in its body, else the module-level one
it returns. A later declaration at the call's scope shadows the binding.
Returned object literals now count as exporting their names for #2162's
unexported-binding rule.
A/B edges added (removed): mealie +176 (-4), excalidraw +156 (`const { t } =
useI18n()`), halo +58, kit +34 (-14, `validate` now the validator's own),
elk +19; trpc byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The sealed-module rule only covered modules exporting nothing. Per symbol
now: a JS/TS top-level binding declared by its own statement (function,
const/let/var, class, interface, type, enum) in an ES module is reachable
from another file only if it's exported — the `export` keyword (node flag or
its line), an `export { a as b }` list, `export default x` or
`export default { a, b }`. Classic scripts, CommonJS, `declare global`,
`.d.ts`, qualified members, object-literal members (zustand store actions)
and `proto.x = function x()` are exempt. Applied at the reachability gate,
so the winner is rejected rather than another promoted.
A/B (edges removed / added): zod -229 (package `z` imports → a local `z`),
excalidraw -66 (DOM `Element` → a test helper's type), kit -50, typeorm -47
(`import { ColumnMetadata } from "typeorm"` → a fixture's local), trpc -26,
hono -8, axios -1; express byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
tree-sitter-javascript can't parse Flow annotations; `render(): React.Node`
ended a class early (segmented-control's component had no methods). A
`.js` / `.jsx` whose leading comments carry `@flow` (not `@noflow`) now
detects as `tsx`, and the TS extractor's offset-preserving preParse blanks
Flow-only syntax for those files: exact object `{| |}`, a maybe type's `?`,
an inexact object's bare `...`, `import typeof`, `opaque type`. preParse is
hoisted before the kernel, so both paths parse the same bytes;
kernel-parity now routes .js/.jsx through detectLanguage too (RN core
Libraries: 0 diffs over 641 files). Grammar preload adds tsx whenever
JavaScript is present.
Parse errors over 400 RN-core Flow files: 10,626 (JS grammar) → 391 (TSX).
A/B edges: RN core Libraries 29,649 → 38,194 (+12,639 / −4,094, the
removals mostly `root.render(…)` → the one DrawerLayoutAndroid::render the
old parse left, and edges re-keyed onto recovered methods);
segmented-control +35/−5; express and react-native-netinfo byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Read at the site:
- a later link of a chain (the extractor keeps one receiver level; the line
shows the dot) reaches a member whose owner the receiver chain is named
after (call / type arguments dropped: `proc("x").call()` → proc,
`checker.value.onWrite` → checker), or a same-file member; never a package
object's function unless it is a Scala 3 `extension` method;
- a name the enclosing def binds (parameter, val/var/def, lambda / for param)
is only a def inside that function;
- otherwise a member of the types around it, an anonymous subclass's bases
(`new OptionParser[C]("x") { head(…) }`), their extends/with supertypes
(source-read heads), same file, or an imported object (`import Foo._`,
`import Foo.{bar}`); a value import (`import builder._`) leaves the file
unjudged.
A/B (edges removed / added): cats -1693/+678, sttp -887/+271, munit
-265/+175, scopt -245/+78, os-lib -115/+43.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The README said every bridge hop carries `metadata.synthesizedBy`, but only
the synthesized channels (rn-event-channel, fabric-native-impl) did; a
resolver-made hop (Swift↔ObjC, RN legacy / TurboModules, Expo Modules JS)
carried only `resolvedBy: 'framework'`, and `expo-module-extract` named
nothing that exists. The framework loop now adds `metadata.framework` (the
resolver's name: swift-objc-bridge, react-native-bridge, expo-modules-js,
fabric-view, rails, laravel, …) and the README says what each kind carries.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- FastEndpoints: an endpoint class (`: Endpoint<…>`, `EndpointWithoutRequest`,
`Ep.…`) declares `Get(…)` / `Post(…)` in `Configure()`; each becomes a route
linked to the class's own HandleAsync / ExecuteAsync (the bare-member scope
from #2151 keeps two `List` endpoints apart). A constant path
(`CreateContributorRequest.Route`) is read in postExtract from wherever the
class declares it; `$"/{nameof(Project)}s"` reads as `/Projects`.
- `app.MapGet("api/todos", …)` is named `/api/todos`.
A/B: ardalis/CleanArchitecture 0 → 24 routes (+24 edges); eShopOnWeb and
eShop only re-key routes whose path gained a leading slash; realworld and
jasontaylordev/CleanArchitecture byte-identical.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>