* fix(csharp): walk field and property initializers as the member
Field declarators and property `= initializer` values were skipped by
both extractors, so `private readonly ILogger _log =
LogManager.GetLogger(typeof(X));` linked nothing, and a method or class
used only from an initializer looked unused.
- tree-sitter.ts / csharp.rs: walk each C# field declarator whole with
its field on the stack, and every property `value:` (not only
`=> expr`) with the property on the stack. Calls, instantiations,
static reads, lambda bodies and fn-ref candidates (varinit included)
belong to the member; the fn-ref scan skips the walked subtrees, so
each candidate is captured once. Attributes stay unwalked.
- A target-typed `new()` that is the initializer instantiates the
declared type (`List<Foo> _items = new();` -> List). In bodies it
stays invisible, as before.
- name-matcher.ts: a .NET type position never names a `constant` (the
kind `const` / `static readonly` fields get). Walking initializers
exposed `new Version(5, 18)` binding to a `const string Version` and
`static readonly Meter Meter = new(...)` instantiating itself.
Kernel/wasm parity: 0 diffs on serilog, Newtonsoft.Json and jellyfin,
and full-index dumps byte-identical between the two arms. No
EXTRACTION_VERSION bump: #2345 already moved it to 28 this release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): credit the report and contributor behind the constant change
The type-position change here is what issue #2337 reports (`new Station
{ … }` unresolved beside a `private const string Station`) and the same
one-line change as @drakeo338's #2339. Verified on the issue's own
three-file repro: the `instantiates` edge to `Demo.Core::Station`, missing
on main, is present with this branch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Indexing CPython took about three times as long on 1.6.2 as at 290e03f
(193 s vs 59 s wall, 8.3 GB vs 3.5 GB peak on a 16-thread Windows box).
A CPU profile put ~290 s of the resolver workers' 412 s on two Python
checks that first shipped in 1.6.2:
- pythonExternalWrites (#2291) read every .py file once per module
global its own module types. CPython has 2,375 Python files against
the resolver's 1,000-entry content cache, so every read went to disk
(184 s).
- isPythonLocallyBound (#2198, #2219) re-stripped the calling file for
every (function, name), and, asked once per same-named candidate by
fitsPythonCallShape, re-derived the enclosing function each time:
3.55M calls for 53K distinct answers (104 s).
Now:
- A global's own module is read first; when its bindings already leave
the type unknown (319 of 379 globals on CPython), no other module is
read.
- One pass per resolution indexes which Python files spell a name after
a dot or a quote, and which write through .__dict__; the write scan
visits only those files, in the same path order. Comment stripping
only blanks text, so any write the scan accepts is spelled that way in
the raw text; a non-ASCII name still reads every file. Index keys are
flat copies (a regex capture would pin its whole file).
- The repo files an import names are resolved once per mapping, in a
WeakMap that lives as long as the resolver's import cache keeps it.
- isPythonLocallyBound keeps the current file's stripped lines and
per-name module-level answer, and answers a ref once.
Verification: nodes, edges and unresolved_refs dumps of CPython and
pretix are byte-identical to 6560052a. Medians of 3 interleaved CPython
runs on a loaded machine: 290e03f 100 s / 271 s CPU / 3.3 GB, 6560052a
322 s / 801 s / 7.9 GB, this change 123 s / 361 s / 5.5 GB. In the CPU
profile pythonExternalWrites drops 184 s -> 16 s and
isPythonLocallyBound 104 s -> 13 s. Most of the remaining gap to
290e03f on CPython is JS checks running on its bundled minified d3
(matchDestructuredCallResult, #2334; jsFunctionLocalScope from #2226).
__tests__/python-resolution-work.test.ts counts the work instead of
timing it: reads of untouched files, strips of the calling file, and
node lookups with 16 same-named candidates (4 / 2 / 8 with the fix,
19 / 18 / 128 on main). Each count fails when only its own part of the
fix is reverted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Windows a worker thread that ends - terminate(), its own process.exit(),
or the process exiting - while V8's concurrent marker is marking its heap
crashes the whole process (exit 3221225477 / 0xC0000005, no error, no dump).
Bisected on the Windows 11 ARM64 VM: --no-concurrent-marking alone stops it
(18/480 -> 0/480; no other concurrency flag does), but it costs about a third
of indexing speed, so CodeGraph avoids the dangerous moments instead:
- src/worker-teardown.ts: owners terminate a worker only once it has started
(its first message, posted after its modules load - mid-load is by far the
worst moment), and a worker about to exit runs a full collection first,
which finishes any marking in flight (gc reached at runtime, never global).
- Resolver pool / store writer: the worker collects before exiting on
'close' (the normal path - main 21/480 crashed on the VM, now 2/1200), and
the 5 s close fallback never terminates a worker still starting.
- codegraph_status change counts: the worker posts 'loaded' after its heavy
require and collects before answering; a deadline answers unknown at once
but terminates only once loaded (3/720 -> 0/1440), and MCPEngine.stop()
waits for measurements in flight.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The resolve loop boots the worker pool mid-run when the remaining refs'
projected sequential settle (observed per-ref rate x refs left) clears 400 ms.
Load inflates the observed rate, so on a loaded 4-core Windows VM a ten-file
project (19 refs) projected 506 ms for its last 11 and booted three workers in
122 of 240 runs under 24 parallel inits (0 of 80 at 8). The pool only fans
out batches of 1,000 refs, so it resolved nothing; synthesis then waited out
its boot (dedupe-merge 6.3 s vs a 6.5 s boot) and its three extra database
connections pushed the VM's free commit to 11 MB.
Adaptive engagement now also needs 20,000 refs left. tokio-class Rust repos
(~55k refs at ~36 us) still engage; a smaller remainder never repays a
seconds-long boot. With the floor, the same load booted the pool in 0 of 240
runs.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cfml): tag-based calls, wrapped functions and <cfinterface> are indexed (#2091)
Tag-based CFML lost almost all of its call edges. The tag walk sent only
<cfscript> and <cfquery> bodies through call extraction, although the cfml
grammar parses the expressions in <cfset>, <cfif>/<cfelseif>, <cfreturn>
and #hash# (output, strings, attributes) with the same rules as cfscript.
The walk now records each such expression with the scope that owns it
(the enclosing <cffunction>, else the component, else the file) and reads
them all through the existing cfscript extraction in one parse per file:
the expressions are copied out on their original lines, each ended with a
`;`, and every reference is handed back to its expression's scope with its
column restored. <cfloop condition="..."> is read the same way.
A <cffunction> nested in a generic container tag at component or template
scope (<cfprocessingdirective> in Application.cfc, <cfsilent>) was skipped
because only direct children were examined; it is now extracted (never
through an ERROR node, where a lost <cfcomponent> would misfile methods as
top-level functions). <cfinterface>, a generic tag to the grammar, now
yields an interface node with its functions as methods and an `extends`
ref per comma-separated parent, so `implements` resolves to it.
The tag-based parse tree is now freed after the walk.
Resolution: the CFML/Ruby/C# bare-call scope filters evaluated the
receiver-on-line check once per same-named candidate though only the ref
decides it. With tag calls extracted, that made Mach-II's resolution ~8x
slower; the check is now memoized per ref (edges byte-identical).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): tag-based CFML calls (#2091)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cpp): bound the macro-visibility include walk (#2127)
isVisibleCppMacro walks the call site's translation unit to learn whether a
function-like macro is visible there (#1838). A header whose guard the walk
cannot decide -- `#define X_H 1` (the OpenSceneGraph / osgEarth idiom, which
guardsItself does not read as a guard), or any header reached under an
unknown `#if`, where neither its guard nor `#pragma once` settles -- was re-scanned on
every inclusion path, and every re-scan pushed its define events onto the
cached timeline again. On a layered include graph that is 2^depth scans and
2^depth timeline entries: "Resolving refs" died with "Ineffective
mark-compacts near heap limit" at the first ref whose file reached such a
tree, at the same ref whatever the heap size.
The walk now keeps a version that every observable change bumps
(definitions, `#pragma once`, the macro-name set). A re-entry with the same
inherited truth, while the version still equals that of an earlier visit
which itself changed nothing, is skipped: it would start from the same state,
take the same branches and change nothing again, and the events it would push
repeat each macro's current state, already its last event. Include cycles cut
by the recursion stack are recorded per visit and must still be cut for a
skip. A hard budget of 1M directive events per walk bounds what is left;
past it the timeline is unknown and nothing at or after the cut line is
suppressed, so the budget can only fall back to ordinary resolution, never
invent a macro.
Answers are unchanged: 20,000 random include graphs (guards bare / valued /
pragma once / under flags, #if/#elif/#else, #undef, cycles) give identical
isVisibleCppMacro results to the previous walker on 1.25M queries, with
about one re-entry in eight skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 73db32f81a)
* docs(changelog): credit the C/C++ macro walk bound
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(resolution): resolve method values on untyped Python module globals (#1820)
A method value whose receiver is a module global without a static type
(`thread_pool_exec(settings.conn.fetch, ...)`, where `conn = None` is
rebound by `global conn; conn = Backend()`) resolved to a `variable` node
and produced no edge. The global's type is now the set of classes its
module assigns to it, at module scope or in a function that declares it
`global`. One class resolves to its own method; several bind to the
nearest declaration every candidate inherits, as a base-typed receiver
does.
No edge (a wrong callback edge is worse than none) when:
- any binding of the global in its module is not a whole constructor
call: a factory, a conditional, a tuple target, `for`/`with`/import,
a star import, or an annotation the constructor contradicts;
- the caller or an enclosing function binds the name itself: parameter,
assignment (any target position), loop, comprehension, `as`, `case`
pattern, lambda parameter;
- the receiver is a deeper chain (`settings.conn.pool.fetch`);
- the importing file rebinds the name, or imports it from two sources.
Statements are read with their continuation lines, and only statement
lines (bracket depth 0) can assign. Not seen: rebinding the global from
another module (`settings.conn = X`) or through `globals()`.
`pkg.mod.Cls` now resolves through `import pkg.mod`, unless two namespace
imports share the last segment.
Python import mappings also read parenthesized from-imports
(`from x import (\n A,\n B,\n)`), which previously yielded the
single name `(` and hid every class imported that way from receiver and
inheritance resolution. Comments and docstrings are stripped first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 0aab32a18b)
* fix(resolution): account for writes to a Python module global from other files (#2074)
The module-global receiver type was read from the global's own module only,
so `settings.conn = Decoy()` in another module, or `globals()["conn"] = X`,
left a stale type and a wrong edge.
- A production write `<module>.<name> = Cls(...)` from another file joins
the type set (resolved in the writing file); any other production write
(another value, a tuple target, `setattr`/`patch.object`) makes the type
unknown. The module is matched through each file's imports, including
aliases and relative imports.
- Test files install doubles (`settings.conn = MagicMock()`,
`monkeypatch.setattr(settings, "conn", ...)`): they do not change the
production type, but a ref inside such a test resolves nothing.
- `globals()[...] = ...` with the global's name or a computed key, and
`globals().update(...)`, in the global's module make the type unknown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 2055711226)
* fix(resolution): match a module global's writers by file, not dotted suffix
Review follow-up to the cross-module write scan.
- A write now lands on the file its import names: relative imports resolve
exactly, absolute ones by path suffix; when a spelling could name another
file sharing the tail (`x/settings.py` and `y/settings.py` for
`import settings`), a write through it makes the type unknown instead of
feeding or clearing the wrong module.
- `import a.b` binds `a`: the module is spelled `a.b`; the mapping's
last-segment name is not treated as an alias of it.
- Test doubles are recognised by the narrow test-suite set plus any
`conftest.py`; examples, fixtures and benchmarks are production writers.
- Writes inside `if __name__ == "__main__":` are script code, not module
state, in the global's module and elsewhere.
- Namespace-dict writes: `globals()`, `vars()` and `sys.modules[__name__]`
are read per statement (continuations joined, strings ignored); any use
other than a literal-key read or `.get`, or a literal-key write of the
name, makes the type unknown. `<module>.__dict__[...]` / `.update(` from
another file does too.
- `settings.conn: Store = Store()` and `settings.conn = (Store())` are
plain constructor writes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 7aab29269a)
* fix(resolution): explicit dotted aliases, one-line __main__ guards, scoped vars()
Review follow-up.
- `import pkg.settings as settings` binds `settings` even though it equals
the last segment; the import mapping cannot tell it from a plain
`import pkg.settings`, so the source line decides.
- `if __name__ == "__main__": stmt` on one line is script code, and a
`globals()` write inside a `__main__` block no longer counts.
- `vars()` is the module dict only at module scope; inside a function it
is the locals, so `return vars()` there no longer makes the type unknown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 0a5fb69797)
* fix(resolution): explicit-alias check matches the exact module, outside strings
Review follow-up: `import other.pkg.settings as settings` or a string
`"import pkg.settings as settings"` no longer marks a plain
`import pkg.settings` as explicitly aliased, which attached a write to the
wrong module.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit a5569a07ea)
* test(resolution): give the Python module-global adversarial table its own timeout
It indexes one project per case, which takes about nine seconds on macOS,
past vitest's five-second default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(changelog): Python module globals and multi-line imports (#2074)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Josh66 <info@aska-systems.de>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Python extractor records `self.get_ip(request)` by its bare name, so the
import strategy matched it to a function the file imports as `get_ip` and
the call never reached the class's own (or inherited) method. A bare-named
Python call written on `self` now skips import resolution; the method
strategies then find it. A plain `get_ip(request)` still binds to the import.
Across allauth, DRF, netbox and mealie this retargets 16 calls, all from an
imported helper to the class's own method; no edge is added or lost.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(php): a class written through a namespace alias resolves to its class (#2256)
`use App\Fields as Field;` aliases a namespace, so `new Field\FirstName()`
names `App\Fields\FirstName`. Expand the first segment through the file's use
map and look the class up by its qualified name, before the pre-filter that
drops names without a `.` or `::`.
(cherry picked from commit 3917de431c)
* fix(php): resolve every qualified class name the way PHP reads it (#2256)
Extends the namespace-alias fix beyond `new`: extends, implements, static
calls (`Alias\X::make()`), names relative to the current namespace and fully
qualified `\Ns\X` now all resolve by their exact qualified name. A name
with no single project class is outside the project, so it no longer falls
through to a same-named guess; a static method the class only inherits is
left to the strategies that walk supertypes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 12c742a917ebd455840c148db1e37c895b9587ad)
* docs(changelog): one entry for the PHP qualified class names fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: drakeo338 <paranoyouz@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A Vapor route whose handler is a trailing closure had no handler symbol and
linked to nothing (vapor's own repo: 76 of 80 routes bound to nothing in the
viewer browser pass). The closure is the handler: its body's calls, each once
with its receiver, are referenced from the route, as an Express inline
handler's are.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Only `XController@action` was claimed and resolved, and the written
namespace was stripped, so akaunting's 'Common\\Uploads@inline' (and a
Route::resource with a string controller plus options) bound 304 of 313
routes to nothing. Any `Class@action` is claimed; the namespace path under
App\\Http\\Controllers is kept and picks between same-named controllers;
a resource reads its first argument and resolves its controller class in
the Laravel resolver (no `use` brings a string-named class into scope).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A Nuxt pages/x.vue or Astro src/pages/x.astro route linked to nothing, so
the viewer's Steps drew a page alone and the routes list never named what
serves it. Each page route now references its file's own component (never a
same-named one — every index.vue is a component named index), an Astro
endpoint its exported verb handlers, and the routing manifest accepts a
component as what serves a route, which also lists Vue Router screens.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Only a bracketed list (and the scoped reader's bare :sym) was read, so
maybe's `resources :family_exports, only: %i[new create index]` drew all
seven RESTful routes — four to actions the controller lacks, listed by the
viewer as routes bound to nothing. Both route readers now share one option
reader for every form Rails accepts.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(js): a CommonJS require and a module path import the file they name
A `require('./application')` was only a call, so a CommonJS file depended
on nothing at file level: Express's lib/express.js showed no imports and
impact missed the files it loads. Local require specifiers are now read
after extraction (both the wasm extractor and the kernel, including its
deferred-decode transport) as `imports` refs from the file, and a JS/TS
module path resolves to its file the way the runtime finds it —
extensions, index files, aliases — which also lands an extensionless
`import './polyfills'` on its file instead of its own import node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(js): read require imports inside each extractor, so kernel parity holds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
An Express handler written inline as `function (req, res) {…}` — the form
Express's own examples use — fell to the named-handler branch, so the route
linked to nothing and Steps drew a lone box for `POST /login`. The handler
is now the registration's LAST argument, inline as an arrow or a function
expression, bare or inside a wrapper call, past a trailing comma; an inline
middleware before a named handler no longer stands in for it.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
resolvePythonModuleMember (`mod.member` after `import mod` / `from pkg import
mod`) looks the member up with pythonModuleSymbol, so a package's
__init__.py re-exports lead to the definition.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
pythonModuleSymbol: a name imported from a module is its top-level
definition, or one the module re-exports by name (`from .tokens import
Token`) or through a star import (`from .users import *`, read from source),
three packages deep, memoized.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
In a TS/JS module the *Service/*Controller convention picks the file's own
class or the convention file beside it (users.controller.ts → users.service.ts),
never a same-named class elsewhere preferred for its file name; anything
farther is the import resolver's or name matching's.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Astro components are used in Astro markup; a .ts / .d.ts type name sharing a
component's name (Playwright's Page, a declaration file's Image) is no
component.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#2243 put the calling file's candidates first, which let resolveMiddleware
pick the file's own `import cors from 'cors'` node; candidates are now
functions, methods, values and classes only.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The middleware/controller/service heuristics took the first same-named node
anywhere; a JS/TS module reaches another file's only through an import or
require (the import resolver's), so they now keep a same-file pick only.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The SwiftUI/UIKit/Vapor resolvers apply to Swift refs only; the shared name
pick never returns the declaring type for an inheritance ref; and the
supertype re-choice prefers the declaring file, then a protocol/interface for
`implements`.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Solidity joins OVERLOADING_LANGUAGES, so retargetSelfOverload moves a call
whose argument count the settled overload cannot take to the one sibling
that can.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A JS/TS module reaches another file's hook or context only through an import
(already the import resolver's), so resolveHook/resolveContext pick from the
reference's own file alone there; an optional call `f?.(…)` is a bare call.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
R looks a call up among functions only; a calls ref named after a base R
function (c, list, df, …) is refused a variable/constant target that is not
bound to a function literal.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
retargetSelfOverload for Swift matches the call's argument labels against
each same-owner overload's external parameter labels (defaulted and variadic
ones optional), instead of the argument count alone.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The extractor names `extension on X` after X; such a node is never a target,
and its members are out of reach from other files (Dart scopes unnamed
extensions to their library) — before ranking in Strategy 3 and as a veto.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
isJavaTypeVisible (before ranking and as a veto): a top-level type from its
package or a single-type/on-demand import; a nested type from inside its
owner, a subtype (anonymous classes by their $anon supertype), an import, or
written through its owner; constructors follow their type; enum constants
only in their enum, a case label, a static import or through the enum.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
isPhpClassVisible: an unqualified PHP class name means the current
namespace's class or the one a `use` imports (none in the project for a
library's); applied before ranking and as a cross-file veto.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
matchReference refuses a method target for a calls ref from a C file: C has
no methods and cannot call a C++ one.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
isVisibleAcrossFiles (before the same-file shortcut) rejects every Go
candidate for a reference its line writes as `pkg.Name` through an import
from outside the module (stdlib or third-party).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
In a .kts file, a bare call reaches a method/field/property only when its
owner is no class the project declares (build logic's extensions on Gradle's
types); the old rule let every member through.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
In isRustNameInScope, a type reference written `Self::Name` is in scope only
as a type alias declared in the enclosing impl/trait block above it, and one
written through a generic type parameter (`V::Value`) names no project item.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
isScalaPackageObjectMemberVisible: a member of `package object X` resolves
from its package and those under it, or a file that imports through it;
applied before ranking (so the visible namesake wins) and as a veto.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
An extends/implements ref that settled on the declaring type is re-chosen
among the other types of its name, the one the written qualifier leads to
(owner path plus file package), or none.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A receiver that is the test's own parameter takes the type its in-reach
fixture returns (`return Cls(…)` or a local assigned `Cls(…)`), so calls on
it resolve on that class, or on nothing when it is a library's; fixtures a
conftest.py star-imports or lists in pytest_plugins are in reach.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
isVisibleAcrossFiles rejects a declaration in a .svelte instance <script> or a
Vue <script setup> from another file; a Svelte <script module>, a plain Vue
<script>, and a type a <script setup> exports stay reachable.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A JS/TS parameter or plain var/let/const above the reference shadows a
same-named function declared elsewhere in the file, whichever strategy found
it; destructured call results, member calls and followed aliases are left
alone.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
One shared pick behind the Django/FastAPI/Flask, ASP.NET, Gin, SwiftUI/Vapor,
Spring and Rust name heuristics: never a function-local declaration, a type
nested in another file's type, or a node the language keeps out of the
reference's file; the reference's own file first, then its directory (not
Rust), then a conventional folder.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Rust resolver's handler/service/struct heuristics took the first
same-named item and then checked scope; they now drop items declared inside
a function body and out-of-scope names before choosing, and take the file's
own item first.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Generalizes the collapsed-chain self veto beyond TS/JS this./window. roots: a
call the extractor recorded by its bare name but the source writes as a member
call on anything other than this/self/super is never the calling method; and a
value's initializer never calls the value itself.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Spring resolver's entity/service/controller name heuristics took the first
same-named class under a conventional folder; they now prefer the ref's own
file, then its package, and never reach another file's nested class by its
bare name.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A TS/JS call written through this.<field>… or window.<x>… reaches the resolver
by its bare name; it resolves to the calling method only when the field is
declared as the caller's own class. A name-scored receiver guess never lands
on the calling method.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A block namespace qualifies only its own body (a nested one is Outer.Inner),
mirrored in the kernel; a using names the project's namespace, never another
file's using; a global using is its own project's; a nested type is reached
by bare name only from inside its owner or a type deriving from it, through
any partial part; visible C# types are filtered before ranking.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A function nested in another function is reachable only from inside it; a
Python name the enclosing function binds is that local's value; a pytest
fixture is a test's parameter only in its own module or under its conftest.
Unreachable same-named functions still count against a lone cross-file guess.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A lone project method now stands for an untyped receiver's member value only
when the receiver is named after the method's class: netbox's
`device=self.parent.device` model-field reads no longer reach a GraphQL
filter's `device` method.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A kind-projector placeholder (`Align[Either[A, *]]`, `Functor[Map[K, ?]]`)
reached the resolver as a type reference named `*`, and exact or fuzzy
matching bound it to the one `*` in the project - algebra's
`Signed.Sign.*` operator - 567 times in cats. A symbolic name in a Scala
type now resolves only to a type or type alias of that name (cats'
`F ~> G`), and otherwise to nothing, whatever strategy runs.
cats -567; sttp unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A bare C# type name could mean any same-named project type. Newtonsoft's
`async Task` tests (`using System.Threading.Tasks;`) bound `Task` to a test
class `Task` in `Newtonsoft.Json.Tests.Schema` 433 times; AutoMapper's DTOs
in `OmmitedDTOModel3` extended `OmmitedDatabaseModel3`'s `BaseEntity`;
Newtonsoft's `BindingFlags` went to its portable-build polyfill.
A type in namespace N is now in reach of a file whose code runs in N or a
namespace inside it, or that imports N: its `using N;`, any file's
`global using N;`, the project files' `<Using Include="N" />`, the SDK's
implicit usings when `<ImplicitUsings>` is on (serilog's own
`System.TimeProvider` polyfill is seen through them), or an alias naming
the type (`using License = AutoMapper.Licensing.License;`). A type in the
global namespace is seen everywhere; qualified names are not judged.
Newtonsoft -529, AutoMapper -72, eShop -4; serilog, CleanArchitecture
unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Rust scope rule (#2124) only checked prelude names; every other bare
name could mean any same-named project item, and a name after any path
(`io::Result`) could mean any at all. The Rust framework resolver's
PascalCase / handler / service patterns bound names with no scope check at
0.7-0.8. tokio's 1,221 `io::Result<...>` went to a private
`runtime::task::Result` alias, 642 `Context<'_>` (from `use
std::task::{Context, Poll}`) to `runtime::context::Context`.
- A type or function from another file is in scope only through a `use`
that binds it (its leaf, `as` alias, or `{self}`) or a glob over its
module; methods and fields (reached through a value), import refs and
module / file targets are unaffected.
- A name a file imports from outside the project - `std` / `core` /
`alloc`, or a crate its Cargo manifests declare as a dependency - is that
outside item. (An inline `mod support { pub mod panic; }` is the
project's.)
- A path names its module: `seg::Name` reaches an item of module `seg`;
a path rooted at std (`std::io::Error`) or at an outside import (`io::`
under `use std::io`) reaches none; `crate::` / `self::` / `super::` and a
project crate's name (`clap::Command`, re-exported) look it up as before.
The path is read anywhere on the line, not only at the reference's column.
- The framework resolver's patterns apply the same check.
tokio -3008 +610, serde -792 +650, ripgrep -602 +247, axum -453 +186, clap
-342 +32, bat -38 +9. Sampled losses: std / core / futures / syn / http /
anyhow imports and paths, associated types (`S::Ok`, `S::Error`, `V::Value`,
`Fut::Output`); gains are same-module items the old first match hid.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#2212 moved a method's call to its own name onto the sibling overload the
arguments fit. The same holds for every caller: a match landing on an
overload whose parameters cannot take the call's arguments moves to the one
same-owner overload they fit - commons-lang's
`HashCodeBuilder.reflectionHashCode(this)` from the three-parameter overload
indexed first to the `(Object, String...)` one, Newtonsoft's
`SetToken(token, value)` from `SetToken(token)`, halo's four-argument
`menuItem(...)` from the one-argument `menuItem`.
Overload sets and arities are read once per target node, and a target with
no same-owner sibling costs one lookup, so indexing time is unchanged
(commons-lang 4.67s vs 4.70s, Newtonsoft 4.04s vs 4.05s, wasm both arms).
C++ keeps only the self-call case: its overload sets (templates, SFINAE
priority tags, `data()` on any container) move targets unreliably.
Targets moved between same-named overloads: commons-lang 2,334, Newtonsoft
697, halo 286, gson 232, okhttp 188, Alamofire 50; nlohmann json and fmt
unchanged. Edge counts unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>