sqlalchemy's package inits (sqlalchemy, sqlalchemy.orm, sqlalchemy.sql) and
orm/collections.py end with `__go(locals())`. Any module-level locals() handed
to a call failed the whole file as a dynamic namespace effect, so every import
there was unaudited and every export UNSUPPORTED: 14,464 real CALLS edges of
sqlalchemy abstained as python_stabilized_export_binding, and their children
(`from sqlalchemy import event`) as python_export_member_dispatch_unproven.
Three rules, each true of Python:
- `f(locals())` / `f(vars())` at module level writes nothing when f is the
module's one undecorated def, bound before the call, whose body never spells
the parameter receiving the namespace, nor locals, vars, eval, exec or a
frame's locals. The body's own effects are walked as anywhere else.
- eval/exec of one plain string literal that is a single identifier only reads
it (pydantic/v1/utils.py `eval('__IPYTHON__')`).
- `alias = globals()` in a function writes nothing when every other spelling
of the alias there is a membership test, an item read or a read-only method,
and the function has no other way to reach it (sqlalchemy exc.py and
ext/automap.py). A module-level alias stays an effect: it is a module
attribute another file can write through.
Referee against SCIP, python, 10 repos: recall 70.5% -> 82.0%, precision
99.3% -> 99.2%. sqlalchemy 42.9% -> 67.6%, pydantic 85.4% -> 90.6%; click,
flask, poetry, django, celery, httpx, scrapy, starlette unchanged. Every new
sqlalchemy SCIP disagreement was listed and read: builtin/typing name
collisions, same-line chain mappings, and narrowed-type selections.
The pipeline gap python-reexport.go_reexport is now required: __go never
spells lcls. Its parameter-write decoy stays forbidden.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A Go import targets the node of its package's directory, and the strict
import path accepted only Folder nodes. The repository root has none: the
Project node is that directory, and its QN is the module of every root
file. caddy keeps go.mod and `package caddy` at the root, imported as
"github.com/caddyserver/caddy/v2", so that import never resolved and every
caddy.X call, and everything typed through one, stayed unknown under the
generic shared_binding_type_fixed_point reason. No cap was involved.
go_package_node accepts the Project node for the root directory in the
module-path strategy, the duplicate-module fallback and the ownership
check, which reads the package directory ("" for the root) from it. The
ownership rule itself is unchanged: a module without a replace directive
or go.work entry still takes the path from the module cache.
caddy against SCIP: recall 83.45% -> 95.89%, real lost 794 -> 200, never
found 229 -> 54, new false 0 -> 0. traefik, minio, cli, helm, prometheus
and etcd unchanged.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Its sibling callback writes through the same parameter, so the shared type cannot take const.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A forward-declared C++ class in view binds to the one definition of that qualified name, by the one-definition rule; with several definitions, to the one whose file includes the declaration. C tags have no linkage and stay abstained. A forward in view outranks a short-name match in another namespace, which removes false edges such as lldb's Stream to llvm::yaml::Stream. Color::RED, gfx::Blend::ADD and typedef'd enum values bind.
Repairs: an #include in an enum body beside a #define no longer breaks the rest of the file; a brace opened in one #ifndef block and closed in another, as DeclSpec.h does, no longer costs the file its namespace; #include inside a namespace is read. Whole llvm-project: CALLS 647,135 to 654,085, USAGE 970,146 to 1,015,783, rc 0, 603 s, no quarantine. Changed relations sampled from source: no wrong edge.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Layout only, on the six files whose new lines clang-format would wrap differently. The suites ran on the tree before this commit.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The k8s change of f8bbdc07c, reverted in f344f72a7, left the same-copies quadratic where it was: the pass took 1,192 -> 5,010 -> 17,024 ms at 2,000 -> 4,000 -> 8,000 same-named copies with it and 1,217 -> 4,791 ms without it, and its growth test stayed at ratio 4.00. The references were already cheap (refs=8000 edges=8000); the cost is in another step of the pass. The test goes with the change.
internal/cbm/lsp/lsp_all.c was an empty file a touch created, picked up by 750b68951.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each name of a file walked every import, imports times names. The imports that can change a name's answer are those whose library, or something it exports, declares the name, and those whose library the build's configuration picks; every other import adds nothing wherever it stands. They are found from the libraries declaring the name, up through who exports them, and asked in written order, so each reason stays the one the first deciding import gives. A prefix and an outside import with no filter are looked up by name.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each reference gathered and sorted every same-named object of its bundles. A USAGE reference draws its edge only when exactly one object answers it, so it now stops at the second answer, which is the same rule written without the gather. Any other reference with a copy in its own file means that copy, so it reads only its own file's objects, indexed by file and name. Same-named copies of one directory are linear now.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A chain of one name held every file's private declaration of it, and each lookup read them all: private let logger in every file of a module cost files squared. The table now keeps, for a chain holding a file-local declaration, the others in order and each file's first own one, and the seven loops that skip invisible privates read that view: the same declarations in the same order, the others never read.
A name no declaration of the project has, and no closed protocol's member, can only find whether a type's chain leaves the project, which is the type's answer and not the name's. It is walked once per file per type. This keeps extension A: P bases linear now that the chain walk has no bound.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Bases and mixins of Dart, PHP, Swift, Scala, Ruby and Perl classes, a PHP variable's writes, a Python function's returns, the files a shell process sources, the C# using-directive walk and the headers a C translation unit reaches were fixed arrays: past them a declaration was dropped or its class went open. They grow on the walk's arena now. A shell command asks the files that declare its name instead of every file of the process.
The binding walks, the source adapters and the proof passes each pass over a file a bounded number of times, and their node and visit counts voided a large generated file whole. Only their nesting guards stay. A Rust trait's method names are no longer cut at 63.
Tests: a class of 70 traits, a variable of 12 writes, a class of 40 bases, a process of 300 sourced files, the seen set's growth and depth guard, and the extension-named imports of item 4, which bind nothing. The chain test of item 1 now measures the walk alone, and the barrel's class is no substring of another needle.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
CBM_SOURCE_CHAIN_MAX was a fixed array of 128 names: past it a class chain or a Dart barrel abstained because a counter ran out. The seen set now starts inline and moves to a table on the walk's arena, with constant lookups. Recursion was bounded by that array too, so each recursing walker now keeps a depth, with a guard of 1024 levels for the stack.
A Dart barrel read its export list for every name of every file, which only the old bound kept near linear. A name's walk now starts from the libraries declaring it and goes up through who exports them, without recursion, so a barrel's width costs nothing.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
GCC's production build refused the null %s, with -Werror. Also the Lua and Shell adapters' cppcheck items: an always-false check and three scopes that can narrow.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Elixir and Erlang made a composite value a CALL_REFERENCE; a dozen walks that grew with the square of the input now read an index once, with the graph unchanged on 12 fingerprints across nine repositories.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each call's spawn check read the file's import rows to find the one its callee's head names, in every language with a spawn table, on both drivers. A Tcl script of 32,000 `source` lines asked that 32,000 times and spent 1.1 s on it, and a call to a name a table lists read the rows once more for its module.
A file's calls now ask a table built on the first question: a local name's first row with a path, and for each module a table names, whether a row imports it. It lasts one file on one thread and answers only for the rows it was made from. Anything else, a name too long for the buffer, or memory running out, reads the rows as before.
complexity_spawn_match_is_linear_in_a_files_imports covers a repeated callee, distinct callees and a module check. complexity_spawn_file_index_answers_as_the_rows_do compares the two routes across languages and callees, with rows lacking a path, repeated names and rows of another file. Numbers and identity: the lane report.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The last dot ends an import's local name, so every `source ./a.sh` row is named sh, and every `part 'a.dart'` dart. All of a file's rows then conflict, and each one cleared all of the name's IMPORTS entries, which the row before it had just cleared. One shell file of 16,000 `source` lines spent 3.8 s in its import map, and one Dart library of 16,000 parts 3.7 s.
Each name now clears them once. Nothing else can add such an entry after the first row: edges are all read before the rows, and a name no edge mapped has none. The map holds what it held.
complexity_import_map_same_local_name_is_linear asserts the map's contents at both sizes. Numbers and identity: the lane report.
The extension as a local name is recorded there, not changed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The oracle treats an edge nobody listed as wrong: the struct values and the function in the shorthand case are real, and the second body's call is the file's second occurrence.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
They ship the test runner itself as the fake release, and it is now 525,426,472 bytes against a limit of 524,288,000, so the update reported a binary missing from the archive. The limit is right for a release and stays. These two tests lift it for themselves through a seam, and a new test pins that an archive over the limit is refused, which nothing did.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The direct writer's tables point at CREATE text the stage owns, and finalize runs whether the stage worked or not. On failure the stage was freed first, so finalize built sqlite_master from freed memory: heap-use-after-free in importance and pipeline_semantic_manifest_repro, whose rejected publish reaches it. The caller already frees the stage on every path, so it now gets the stage back either way.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A name that is not a type's own member asks each of its bases, so a type with many conforming extensions cost bases x names: 16,000 `extension A: P` took 157 s in resolve. Past the chain's bound of 128, every further base answers open, so the loop goes on only to reach the answer it already has.
It now stops there, once the bound has passed and the answer is already open. Nothing past that point can change the result: a base can no longer be found or be ambiguous, and an open answer returns the same whatever `declared` or `result` hold. The `extension_only` scan also stops at its first declared record.
complexity_swift_type_bases_are_near_linear: 3.84 on the old walk, 2.00 now.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Every file that imports a barrel read the barrel's whole export list again, though one name's walk stops at the chain's bound of 128 libraries. With the barrel listing the project, that is files x exports: 16,000 libraries took 39.7 s in resolve.
Exports are now read when a walk first reaches them, and a walk stops once the bound is passed, since no further library can then be visited or change its answer. So `dart_export_graph_not_walked` is still what a name past the bound gets.
Left as it was: an export that a `show` or `hide` rules out costs a filter check per name and does not count toward the bound.
complexity_dart_barrel_exports_are_near_linear: 3.71 on the old read, 1.94 now.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
NASM and ObjectScript routines are flat: each statement looks back over its earlier siblings for the label above it. A long stretch under one label was quadratic in steps, and each step was itself a walk from the first child.
The walk reaches siblings in order, so a search now stops at the sibling the last search under this parent started from, and what that one found holds for everything before it. One memo per ancestor level, for NASM's climb. Which label a statement gets is unchanged.
complexity_flat_preceding_label_is_linear: NASM 4.00 on the old walk, 2.00 now; ObjectScript 2.00 now.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
For every route call, go_find_binding walked back over the statements before it to find what the receiver was bound to, and each step back was itself a walk from the block's first child. A function of 16,000 `r.GET("/x", h)` lines spent 91 s in extraction, and 16,000 `g := r.Group("/g")` pairs 207 s.
A block's bindings are now read once, the first time a route call in it asks: every name each statement binds, by name and then in source order, in `scratch`, so it ends with the file. A question is a binary search for the last binding before the statement that asks. Which statement answers is unchanged: rebinding, shadowing, `var` lists, tuples, a name with no value and function boundaries all behave as before, and running out of memory still gives no prefix rather than a partial one.
complexity_go_route_bindings_are_near_linear, old walk -> now: see the lane report for each row. Identity: 12 fingerprints identical on gitea (1,054 `m.X("/...")` registrations in two files) and on a generated tree of 834 routes that composes each of those forms. gitea registers on one receiver and has no `g := m.Group(...)` binding in those files, so the generated tree is what covers the group forms.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A source adapter asks which definition of a name belongs to each declaration, and the answer walked every definition of that name in the file. A name can repeat all through a file, as a script's `x=1`, a chunk's `local ok` or `init` in generated code do, so the join was quadratic in the repeats. Every adapter goes through these three calls.
A name's definitions are now sorted by first line, with a link from each to the nearest earlier one still open where it starts. The answer is a binary search, then that path, which is as long as the nesting there. The tie-break is unchanged: the tightest span, and of equal spans the latest in the file's own order. `cbm_source_def_qn_of_name` keeps its answer per name.
complexity_source_same_named_definitions_are_near_linear covers Lua functions and locals, Shell, Vim, Tcl, Swift, Dart and Haskell. See the lane report for each row's ratio on the old walk. Graph output is unchanged: 12 fingerprints identical on neovim, redis, koel, Alamofire, bloc, plug, cowboy, gitea and a generated tree of nested same-named definitions.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
ts_node_prev_sibling and ts_node_prev_named_sibling walk from the parent's first child to the node, so asking once per child of a wide parent is quadratic in sibling steps alone, and a walk back is worse. Sites that do it per definition or per statement include the decorators before a method, a Dart function_body's signature, a C `TEST(x) {}` body and a Dart selector's callee.
Both now route through the index, like ts_node_parent and ts_node_child, so every file that includes syntax_index.h gets them, including a call added later. The answer comes from the list the index already holds. A zero-width node keeps tree-sitter's own answer: its place among byte offsets is what ts_node__prev_sibling decides, and the list cannot.
complexity_syntax_index_prev_siblings_answer_as_tree_sitter_does compares both calls with tree-sitter on every node of eight sources, parse errors and MISSING tokens included. complexity_prev_sibling_walk_is_linear: plain 4.00, indexed 2.00.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The extras path in resolve_calls called any callable a site names a CALL_REFERENCE, with no composite check. So `flag && &a/0`, `if flag, do: &a/0, else: &b/0` and `case Flag of true -> fun a/0; false -> fun b/0 end` each gave CALL_REFERENCE edges, which call_reference_language_complex_contract forbids: the value is one of several. This is the Perl bug in the other carrier.
The adapter now says so, as a carrier's may_be_call_reference does: an extra site carries `composite`, and such a site is USAGE. It holds under `&&`, `||`, `and`, `or`, `andalso`, `orelse`, and among the branches of `if`, `unless`, `case`, `cond`, `with`, `try`, `receive` and `maybe`, parentheses and blocks aside. A direct argument, a bound name, a return, a list or tuple entry, a message sent and a closure's body are one value again and stay CALL_REFERENCE, including inside a branch.
Ruby and Dart are not affected, and the contract suite now pins them. Ruby's `method(:a)` binds nothing, so it is no edge. A Dart tear-off is USAGE in every form, which also means a direct one never gets CALL_REFERENCE: a recall gap, not a false edge.
RED with the two assignments reverted, on the oracle with 2c3967d88: elixir-composite wrong=17, erlang-composite wrong=15, and both new contract rows fail on `reference=1/1`.
plug, cowboy and bloc: all 12 fingerprints identical before and after, so none of their 8, 19 and 23 CALL_REFERENCE edges was composite. No recall is traded on them.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
`struct X;` directly under `#ifdef` has the directive as its parent, and only the translation unit above it says the tag is being declared. The directive's own name climbs to the root first and settles that path, so without `!bodyless_tag &&` the tag's climb stops at the directive and leaves a usage row for a declaration. The guard came in during a merge, by reasoning, with no test.
Removing the guard fails this at `lone_under_ifdef`: 1 row, expected 0.
The decoys count raw rows: an active branch is read twice, raw and preprocessed, so `#ifndef OTHER` gives two rows in all.
Not covered, because it is not the guard's doing: `struct X;` under `#else` stays a usage row with or without the guard. Its `alternative` field trips is_value_field first.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
swift_closure_signature returned a pointer to a local array for () -> Void, and the signature was stored and read long after, so what a closure's parameters meant came from a dead frame. That signature is everywhere in Swift. cppcheck found it; the test goes red under detect_stack_use_after_return=1, which the normal test run turns off.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The exemption for edges with their own producer compared json_extract(...) with =. For an edge without that key the comparison is NULL, NOT (NULL) is NULL, and the row left the unattested-edge audit: every CALLS edge to a Function lacking strategy, every USAGE into a Table, View or Model lacking via. IS keeps them in. resolver_quality_oracle_rejects_mutated_occurrences_and_projection caught it with an edge that has no occurrence row.
A Kotlin parameter's written type is USES_TYPE of the class, which the graph now states; the fixture still held it as a USAGE known gap.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Both drain workers ended without cbm_destroy_thread_parser, so the 24 KiB field-name cache of each worker thread was lost on every index, which a long-running server pays for. LeakSanitizer on Linux shows it across 29 suite runs; macOS has no LSan.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The exemption for edges with their own producer compared json_extract(...) with =. For an edge without that key the comparison is NULL, NOT (NULL) is NULL, and the row left the unattested-edge audit: every CALLS edge to a Function lacking strategy, every USAGE into a Table, View or Model lacking via. IS keeps them in. resolver_quality_oracle_rejects_mutated_occurrences_and_projection caught it with an edge that has no occurrence row.
A Kotlin parameter's written type is USES_TYPE of the class, which the graph now states; the fixture still held it as a USAGE known gap.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
enum E : int; and enum class E; inside a block reached c_bind_local_tag_and_enumerators with no body, which then read the enumerators of a null node. A worker crash has its file quarantined and the index still reports success, so one such file was dropped silently; a second exhausted the retries and failed the whole index, as clang's own tests did on llvm-project.
The lone-tag rule keeps its meaning: the name still hides the outer enum from there on.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Lua CALLS on neovim go from 4 to 19,685 against 20,307 at baseline, whose count holds wrong targets: lexical scope and value flow through aliases, function M.f, return M, require via package.path forms or a unique lua, src or lib root, and __index with @class parents. Whole-file gates on load, _G, goto and ... are gone, because none can rebind a local; _ENV, setfenv and debug.setlocal still abstain. New adapters give Vimscript, Shell, Tcl and Make proven edges: neovim vim CALLS 0 to 3,365, redis Tcl CALLS 0 to 2,815, with a function table per process following source.
A Vue or Svelte script is a module whatever its markup says: koel Vue CALLS 2 to 1,484, IMPORTS 0 to 1,650. Members of an imported object literal, and const { open } = useThing() where every return names it, resolve. An adapter may now declare parse errors local: 74% of Tcl files have one. About 490 edges read from source, one wrong and fixed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Graph fingerprints stayed identical on 27 of 27 repositories across 15 languages on the integrated tree, while elasticsearch went from 367 s to 207 s, TypeScript 248 s to 70 s, kilocode 112 s to 34 s and django 43 s to 15 s. Elasticsearch's charged peak falls from 29.8 GB, 7.3 GB over budget, to 16.6 GB within it. A 990 KB Kotlin file of unclosed nested objects goes from over 50 minutes to 4.3 s, a bug main had too.
Resolved so both sides' behaviour survives: the projection deletes every controlled type in one walk while leaving edges its exemption claims. The Dart callee rule reads through the walk's linear sibling lookup. The binding climb's memo stands aside for a bodyless C tag, whose answer can lie above a settled ancestor, as in struct X; directly under an #ifdef. The source adapter keeps the repairing parse, so it reads the tree extraction read.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A narrowing covers its whole function, so the search for the one covering a receiver only gets long across functions narrowing the same name. The first fixture kept every narrowing in one function and stayed at 1.61 on the old scan, so it could not fail. Across functions the old scan reaches 3.65.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Alamofire's voided files go from 20 of 101 to 0, Vapor's from 49 of 277 to 6, through a same-length Swift parse view. Baseline edges kept on Alamofire: CALLS 1,049 to 3,027 of 4,698, USAGE 188 to 2,804 of 9,020; of the 978 CALLS still lost with nothing like them left, 28 of 32 read were fake. Swift private types are keyed per file, which also fixes a false edge between two files declaring one private name. Dart class headers, constructor defaults, super and exports resolve. PHP adds a project trait beside an outside one, and function return types.
Swift property QNs now carry their class, as Kotlin's do. Swift init, deinit, subscript and enum cases gain nodes, as do Dart mixin, abstract and accessor members. Swift IMPORTS is now a supported relation.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each test measures a counter at n and 2n and asserts a ratio near 2, so no clock decides it. Each was run against the old scan and failed at a ratio of about 3 to 4. Equivalence tests pin the indexes to the answers of what they replaced: the syntax index to tree-sitter, name rows and the registry tail to a scan, the parse memo to a fresh parse.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A 990 KB Kotlin file of 90,000 unclosed `object A {` lines held an index run for over 50 minutes, and main has the same cost. Declarations left open sit side by side under one error node, so each question about a child walks that node from its start. Extraction has an index for this, but the passes that parse again did not: Kotlin's, C's and C++'s cross passes and Rust's source facts now open one, and the TypeScript, Kotlin and C proofs, compiled apart, now ask through it. Dart's next-sibling test uses the walk's cursor. That file now indexes in about 4 seconds.
The same lines closed are real depth. Each identifier's usage classifiers climbed to the root, and each definition's decorator lookup started from it. A climb that reaches the root undecided now settles its path for everything below it, so the next one stops where it meets that path: a level's answer depends only on the path through it, and a node with any extent lies in one child of its parent. Decorators ask the index for the previous sibling. What is left at great depth is the qualified names themselves, whose stored length grows with depth.
Each path went from about 4x to about 2x work when the input doubled. Answers are unchanged: all 12 graph fingerprints match on every repo measured.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The TypeScript proof scanned a file's imports for each callee and annotation, and every narrowing of a path for each receiver on it. TypeScript's own checker.ts names over a thousand imports in 54,000 lines. Imports now use the file's rows, and a narrowing lookup is one binary search: entries sorted by path and start carry the furthest end so far, and one covers a position exactly when that end passes it.
A Rust module's uses were walked for each local item found, each imported name and each trait a method call asked about. Long lists now answer from rows by local name and by last segment, in list order.
Each of these went from about 4x to about 2x work when the input doubled. Answers are unchanged.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The projection that decides whether results spill was fitted before the strict resolver, at 160 bytes per reference. Resolve now grows by up to 3,250 bytes per reference, so elasticsearch projected 2,534 MB against 26,479 MB real, kept its results in memory, and reached 29,755 MB charged against a budget of 22,488 MB. No phase after extraction can spill.
The refit is 3,400 bytes per reference, fitted to Java, the most expensive language measured. Elasticsearch now spills by itself and peaks at 16,833 MB charged, with no slowdown and all 12 graph fingerprints the same as in memory. Spilling changes when results park, not what is resolved, so this is no work cap. It over-reads other languages, which only costs disk reads: kubernetes projects 18,479 MB for 8,384 MB real, and still keeps results in memory at the full budget.
Nothing updates the constant. A later change that costs more per reference has to refit it.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The shared resolver built each file's binding index up to four times, and the preparation passes reparsed every file on one thread. One cached index now serves them, and a parse batch parses ahead on all workers. Python's root facts and the builtins' file list stop walking per file (both 4.00x to about 2x), and the struct field fold joins by class instead of scanning a file's definitions per struct (4.00x to 2.00x). lsp_cross_prepare on django goes from 7.4 s to under 1 s.
C# reference-assembly files keep their deferred pass, which parses them one at a time as before.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The language passes scanned a file's imports for each use and the registry for each definition while it filled, so their work grew with the square of a large file. Rows chained by name now answer those questions in the order a scan found them, and a registry can index what was added since its last index in a scratch arena, with the same first-registered answers. Each path below went from about 4x to about 2x work when a file doubled: imports in TypeScript, JavaScript, Java, Kotlin, PHP, Rust and Go, Python's imports and statements, locals in Rust and the Java, Kotlin and C# walkers, Rust module children and impls, TypeScript methods per type, Java registration and overload patches, Rust derives, Go generics and C# signature patches.
Answers are unchanged: rows hold the same order, and duplicate names still resolve to the first registration where a scan did.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Writing evidence row by row through SQL was the largest single cost of an index: 12.9 s of writes on django, 35.6 s on kubernetes. Rows now go straight to b-tree pages and digests run in parallel, the proof pool keeps a memo of the texts of a session, and hot keys no longer go through snprintf, which takes a process-wide locale lock on macOS. Writes take under 0.4 s on django and under 0.9 s on kubernetes. Databases shrink: kubernetes 4,364 to 4,162 MB, django 932 to 869 MB. Nothing readers use is removed; the same rows are stored.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
ts_node_parent and ts_node_child(n, i) walk from the root or the first child, so any pass over a flat file was quadratic in its top-level items: child steps grew 3.99x when flat.py doubled, 3.98x for flat.ts, 3.94x for flat.php. Passes now read a per-tree index built on first use, which answers exactly what tree-sitter answers, and every step count above grows 2.00x. The index is scoped over the whole of extraction. A worker keeps its parse of a file for the other passes over that file, so a file is no longer parsed once per pass. C#'s file-scoped namespace is looked for once per file instead of once per class, and the doc memo keeps a wide root cached.
No graph content changes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A stranded static function lost its static flag and read as externally linked, so a call could bind across files: fixed with a decoy. Tag uses such as struct cfs_rq *cfs_rq now bind, kernel subtree USAGE 44,251 to 113,857, along with cast macros as receivers, C++ unions as classes, and two-headed function repair. Macro hand-off walks keep a seen set on macro and position: on doubling depth the work counter goes 35 to 47 where it was 155 to 8,225 without one.
Withdrawn as not provable: a rule binding a macro in one configuration branch and a function in another, because the call exists in only one, costing kernel subtree CALLS about 1,041; and a raw define beside a missing header, which that header may undefine, costing neovim about 5,500 edges that look true. Canonical lint passes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Projection deleted every controlled edge the resolver had not recorded, including route registrations, Helm includes, Kubernetes references, SQL lineage and Ansible notifies. A narrow exemption now needs the producer's own via marker and the target's label together; a forged-looking CALLS still goes, by decoy test. Over 47 repositories CALLS into Route go from 4,315 at baseline and 0 before this to 1,146, without client calls and string methods: django 1,206 to 0. Helm includes return to 3,365 and Kubernetes references to 3,936.
One empty .tf or terragrunt.hcl no longer aborts the whole index. One templated Ansible handler no longer voids every notify in the project, nor one unfollowable .env value every $ image in a compose project. Go method-value and ASP.NET method-group handlers no longer bind by name.
For review: a receiver named router or app, with a literal path and a handler, counts as evidence for a Route, which is name-based and an exception to CALLS meaning a declaration, as is a Helm define. A dbt model target in SQL is kept without package namespace proof. The test audits skip the projection table's rows.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
source_damage_scan runs on a resolve worker when a source adapter reads a file with parse damage, and it fills the thread-local bitset cache of cbm_kind_in_set. extract_worker frees that cache at thread exit; resolve_worker_impl did not, so each such worker leaked it. LeakSanitizer on Linux reported 152 bytes in 3 objects from ks_build in resolver_source_langs, once the much larger OCaml cursor leak was gone. The first run's report was cut before it.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
rust-std-receiver reported wrong=2 projection_errors=1 because its two constructor rows had no target identity, written when the graph had none for a constructor. The go-rust lane's rule now emits CALLS to the struct, and it is true: a tuple struct's name is its constructor function in the value namespace. `EvidenceTier(1)` and `EvidenceTier(2)` bind the one `pub struct EvidenceTier(pub u8)` in that module, and resolver_rust_tuple_struct_constructor_is_a_call pins the named, unit, value and shadowed cases that must not.
The rows now name the Struct node and are required. Naming it brings real_caller's return type into the audit, so `-> EvidenceTier` is attested as USAGE and USES_TYPE, as the matrix does for class mentions.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
callback-parity failed on recovered_gaps=1. The log's QUALITY_MISS for javascript-script-shadow-control was only the last line before the summary: that row is an unchanged known gap, and the row that recovered is callback-perl-coderef. `perlReferenceAccept(\&perlReferenceTarget)` is a direct coderef argument to a sub of the file, and the Perl adapter now proves it, so the CALL_REFERENCE is true.
With the row required, callback-parity reads genuine=10 found=7 missing=3 recovered_gaps=0 on both routes. The sequential floor assertion also covers this pair now, so the exclusion list goes from six to five.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The dynamic lane made resolve_usages call every admitted Perl carrier a CALL_REFERENCE, through a language clause beside the comment saying composite expressions stay USAGE. So `$flag ? \&handler : \&alternate` got two CALL_REFERENCE edges, which call_reference_language_complex_contract forbids for every language with callable references: the value is one of several.
The carrier now says it, as in the other languages: perl_lsp.c leaves may_be_call_reference false under a conditional, a binary operator or a low-precedence logical operator, parentheses aside, and the clause is gone. `my $r = \&own`, a table entry and direct arguments stay CALL_REFERENCE. mojo has 37 such edges and none is composite. resolver_source_langs gets positive and negative rows for each form.
Tests corrected, because the rule is right and the rows were not:
- The registrar in both Perl fixtures was `sub accept`. accept is a builtin and only an import overrides one (perlsub), so the adapter was right to abstain and `CALLS refs.accept` was never genuine. `perl -c` on the old fixture says "Not enough arguments for accept"; with two arguments the builtin runs and the sub does not. It is now `sub submit`, same length, and those rows are required. builtin-not-overridden-by-a-sub keeps the decoy.
- The conditional's USAGE rows named `handler` without `\&`. The carrier and every other Perl row use the `\&handler` span, and the rows were never found, so nothing had checked them. Corrected and required.
- perl_exact_coderef_is_call_reference-1 is recovered and true: promoted.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The dynamic lane's Scala rules recovered these, and the matrix asks for promotion. Each row was read against its fixture and the index:
- `a + b` with `a: Vec2`, `def +(other: Vec2): Vec2`: `a.+(b)`, Vec2.+.
- `(a + b).dot(b)`: `+` declares Vec2 as its result, Vec2.dot.
- `first(ns)` with `def first[T](xs: List[T])`: the top-level def. A generic def had no arity before, so its calls abstained.
No false edge came with them: `x + other.x` on a Double field abstains as scala_value_of_unknown_type, and `Some(...)` as scala_name_not_in_project.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
ocaml_collect_structure created a tree cursor and had no ts_tree_cursor_delete at all. Its one exit after the cursor is the fall-through at the end of the loop, so every struct of every OCaml file leaked one. LeakSanitizer on Linux reported it at adapter_ocaml.c:603 from resolver_source_langs. The other three cursors in the file are already paired.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Kotlin USES_TYPE goes from 0 to 6,131 on Exposed: extraction records type refs, leaving out a supertype's or annotation's head that INHERITS or DECORATES already carries. Call type arguments such as Box<Argument>() now emit. A C# named argument lands on the parameter it names, and a name the declaration lacks rules it out, so overloads such as new Reader(byte[], isFinal: true, state) settle. The default literal fits any parameter. A one-line Kotlin object reads as a class through a same-length parse view.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
cbm_shared_resolver_build creates both and cbm_shared_resolver_free never released them, so every index leaked two hash tables. LeakSanitizer reported it on Linux across 77 suites; macOS does not run it.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
rust_macros kept pointers to its locals in the caller's scan after returning; it now runs on a copy and clears them. path_alias.c allocates through the memory core, 40 raw sites down to 1, with cbm_path_alias_resolve alone staying raw because its callers free its result. Four copies of one import-map cleanup become one helper, 63 raw sites down to 53 in pass_pkgmap.c. The rest reshapes code cppcheck could not follow, without changing behaviour.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
CALLS: redis 28,295 to 32,377, neovim 29,542 to 31,306, whole llvm-project 432,362 to 644,451; USAGE on redis 42,133 to 51,931. Macro replacements are read at the use when every visible definition agrees. Local arrays bind a type, unnamed aggregates get members, ns::Name binds outside its namespace, and out-of-line template members and member templates get nodes.
New graph content: Class nodes named Owner$member. QN changes: out-of-line template members and ns::Foo::bar are Methods. A write through a macro member path records USAGE, not WRITES. False functions such as one spanning 1,445 lines of jemalloc's ctl.c are gone.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
dotnet/runtime CALLS go from 392,440 to 773,575 and USAGE from 709,951 to 1,688,346; elasticsearch CALLS from 1,308,131 to 1,342,695 and Exposed from 20,357 to 23,603. The same type in ref/ and src/ now means the implementation stands for the contract. A reader means its own file's declaration or the only one in its build project, and .projitems counts as a project. A same-length parse view reads spellings the grammar loses: Vector128.cs goes from 0 to 172 methods. Lambdas take their parameters from the callee's single abstract method.
A CALLS edge can now start from a Field node, and calls in C# conversion operators, indexers and property bodies belong to those members. Five wrong edge kinds found while sampling are fixed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
USAGE goes from none to thousands of SCIP-confirmed pairs on Ruby (rubocop 3,322, vagrant 4,488) and to 890 sites on Elixir's plug. dune CALLS sites rise from 6,891 to 43,659: .mli files are read inside sig, includes reach paths below them, and functor parameters are bindings. Elixir's use reads __using__, Haskell's T(..) matches, Zig reads a field's type with its own file's visibility, Scala class-body vals carry their class in the QN.
A Ruby block keeps self only under a core iterator or a project method whose declaration does not rebind it, followed through a forwarded &block, so blocks under unknown gem methods abstain. Several OCaml and Scala false edges from the earlier tree are gone. CBM_INDEX_FORMAT_VERSION moves to 5 because OCaml, Zig and Scala QNs changed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
CALLS recall against SCIP: cli/cli 35.4% to 99.9%, cargo 20.4% to 98.6%, tokio 26.6% to 91.8%, meilisearch 97.1% to 98.4%, prometheus 97.1% to 97.8%, helm 98.2% to 98.6%. A test go.mod declaring the repository's own module path no longer voids every import of it, and replace directives decide. Grammar errors from Go new(expr) and Rust str![[...]] no longer void the file: cargo had lost 477 of 1,374 files. Rust macro_rules definitions are read per package, and calls in nested items belong to the enclosing function.
A Go conversion T(x) is USES_TYPE, not CALLS, though SCIP counts it as a call pair.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
CALLS recall against SCIP: vue 62.9% to 98.0%, vite 62.2% to 97.4%, nest 90.9% to 96.6%, precision 100% and no site contradicting SCIP. An identifier merely named Function or eval no longer voids a file. Workspace packages, tsconfig paths, baseUrl and exports conditions resolve from their manifests. Receivers come from what the file spells. Five false-edge classes found by decoys are closed, one of which predates this round: this in an object literal read as the enclosing class.
A package.json, pnpm-workspace.yaml, tsconfig or extends base edit now declines incremental repair.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
CALLS recall against SCIP on six repositories rises from 80.7% to 95.5%, precision holding at 99.5%. A manifest now states source roots, so a src layout reaches its own package. A write blocks only the name it spells, not a whole package. Decorators keep the declaration unless the source proves the function dropped. Three false edges the baseline also had are fixed: a conditional star's first arm, t.x = make() reading the declared x, and a descriptor read as the instance.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
C writes no binding list to alter now, so the authority test forges one: a property naming a wrong target must still carry no authority. The Python suite ran about 500 full indexes through both drivers and passed the 900 s per-suite cap on Windows, so it is three suites, and rows of one fixture share its index. No assertion changes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Nothing reads it, and a generated header with tens of thousands of includes made one File node 9 MB and its database 13 times the baseline's. Under strict_string_checks that string also made the FTS backfill's LIKE quadratic, so the diagnostic CI lane timed out at 900 s. The test now pins the node's size.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
js_fixture returned its arena by value while the index kept a pointer to it, which only worked where the copy was elided. The parallel harness never freed the Rust project and ECMAScript surfaces. Templates sized exactly to their text overflow on Windows, where cbm_mkdtemp rewrites /tmp/ to the longer temp root in place.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
GCC treats the conditional compound literal inside the context's designated initializer as missing braces, and the Linux build fails on it. A zeroed node is already null, so only a repaired parse assigns one.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Over the memory budget each result is parked on disk and read back only for a moment. The Java, Kotlin and C# declaration index kept qualified names from the freed result, and a resolve worker read them. TypeScript's merged label did the same. Both are found by ASan with CBM_MEM_SPILL=1; every resolver suite now runs clean that way.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The same three comparisons read as one helper, and cppcheck no longer infers a constant from the indent loop. Behaviour is unchanged.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Fetching a child by index walks from the first child, so the audit was quadratic in the statement count, and it runs serially for every ECMAScript file. TypeScript's baselines held indexing that repository for over 28 minutes; it now takes 182 s. The C# reference-assembly fixture binds neither type now that the parse view keeps both namespaces.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Only a direct argument, parenthesized value, standalone reference or initializer hands over one callable. Branches and pairs do not, which is what this test required before it was flipped and what a Java ternary does. A Go result annotation is USES_TYPE alone, like TypeScript, so its USAGE row goes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
With the harness building the index production builds, the reference argument,
the same-package access and the constructor call all bind, and each is what the
rules select: Java and Kotlin share com.example, and no constructor is declared,
so the class stands for the implicit one, as test_resolver_oo.c pins.
The Kotlin alias gap is named after its real cause. The file parses completely, so
the parse-gap name and text were stale. The alias call stays unbound once the file
also declares a class with a member.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The parse view keeps one branch of each #if, which is enough for the graph's nodes.
The scope read that same tree, so a namespace or a type another branch names
differently looked placed and complete. A reference valid in the other build was
then reported as doc rot, where it used to be a graph gap.
When the view hid a branch, keep the file's own parse for the scope. A view that
only blanked `ref` hides nothing and stays in use. RED:
doc_mentions_cs_scope_parse_errors, doc_mentions_resolver_parse_errors.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
An unnamed companion now has a node, but the scope looked a definition up only by
a name token, which it does not have. [Type.Companion] stayed a graph gap with the
node right there. RED: doc_mentions_jvm_kotlin_scope_blob,
doc_mentions_jvm_kotlin_companion_inherits.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Kotlin nested types are named under their outer class and an unnamed companion
has nodes, so the pins move to those names, each confirmed against a real index.
One of them, a zero count on gk.K4.Wrapped.m, passed vacuously under a stale
suffix.
A nested class and a member function of one name now share a qualified name, and
so do a member function and a property. The later declaration owns the node, so
[Holder.Part] and a doc on the earlier twin are graph gaps. No edge goes to the
wrong twin. Both are pinned as known gaps.
The C# parse view reads `ref partial struct`, so those fixtures write it with a
comment between the words, which the grammar still cannot read and the view does
not repair. The plain spelling gets its own positive.
RED until the two doc-link fixes that follow: the slot of an unnamed companion, and
the C# scope of a file whose parse view hid a branch of a conditional.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Kotlin records no USES_TYPE occurrence for a result type, so USAGE names the class there. A
parameter annotation emits neither, so ad60078d4's parameter rows required an edge production does
not make. Dropped those two rows.
Also corrects ad60078d4's message: the PHP reason string was renamed in b821d1506, not aeb5971dc.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A matrix row on a class target brings that class's other roles into the harness
audit. `make(): Widget` and `anon(): User` name the class they also construct, so
the signature's USAGE, and USES_TYPE in Scala and Swift, become required rows at
that exact token.
mkc_c2_csharp_operator_overloads pins the operator scope for overloads stored as
variants, for a spaced `operator -` and for the word form `operator true`.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each row was checked against its fixture source.
Promoted to required, the target is what the language selects: same-class C# await call, Kotlin
suspend call, Kotlin sealed `is` branches with their forbids kept, Java enum methods, the static
interface target with its forbid kept, Kotlin operator plus, the imported Celery instance's
send_task with the foreign decoy kept, RestTemplate literal routes.
Corrected:
- writes_go named a `cache.` package part that a Go root file does not have, so neither the row
nor its decoy forbid could match anything. Both now bind.
- Python and Kotlin constructor rows name the class node. A Kotlin primary constructor has no node
of its own and Python's class call selects the class, as test_pipeline requires.
- FunC and Meson import probes required 0/0 spans. The carrier now records the literal's exact
occurrence, and the probes require that occurrence.
- es_php_include_occurrence_spans_and_sealing_guards pinned a reason string renamed in aeb5971dc.
Reads are USAGE: Go, Java and C# rows list it as required. Their READS rows stay named gaps because
nothing emits READS. Java's count++ stays a gap: its assignment kinds omit update_expression.
Celery's ASYNC_CALLS rows stay gaps with an updated reason: CALLS is proved, the service
classifier does not see that proof.
Adds es_go_annotation_types_are_not_value_usage and es_go_index_assignment_reads_operand_and_index
for the Go role rules. No forbid was removed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
`cache[key] = v` stores an element through the operand's map or slice and rebinds nothing, but it
published WRITES for cache and nothing at all for key. Both are reads now, so they are USAGE. An
array variable is written in place by this form as well; its element type is not known here, so
it reads as USAGE too, which is a missing write and not a false one.
A Go parameter, result, var or conversion type also published USAGE on the same token that
type_refs already carries as USES_TYPE, which es_usage_crossfile_go forbids and the TypeScript
adapter already refuses. One token now has one role. A composite literal builds a value of its
type, a receiver has no USES_TYPE occurrence, and USES_TYPE reads a qualified type's whole
spelling rather than its member token, so those three stay USAGE.
RED: cp_reads_writes_go_global (forbid Set WRITES cache) and es_usage_crossfile_go (forbid
annotation-is-not-value-usage).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The parallel route decides per file whether cross-file analysis runs, and a file with no call
left to resolve was skipped. For Java, Kotlin and C# that also skipped the strict walk, which is
the only source of their field and type rows, so a class that only reads and writes its own
fields lost every USAGE, WRITES and type row in the parallel route. The sequential route has no
such filter, so the two routes disagreed.
C and C++ already had this exception. Extend it to the strict-walk languages.
RED: writes_java, writes_csharp, cp_reads_writes_java_static_field and
cp_reads_writes_cs_static_field found the write in the sequential route and lost it in the
parallel one.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each row was checked against the fixture source and the language's own rules.
Conditional variants (Go build tags, Swift, Erlang, Elixir, Haskell): one node
holds every branch's span, so a body call is that node's call under its authored
variant, and a caller reaches that one node in every configuration. Targets
anchor on the node's stored span. Haskell later branches stay a known gap: the
source adapter walks the raw parse, which holds only the first branch of a #if.
C# same-name classes: all seven member rows promote, the constructor call under
`using Contoso.Threading` gets its own required row, and the edge checks now pin
the bound target with the decoy still refused. `new Thing()` on a partial type is
a known gap: no one node is that type.
The parallel harness now builds the declaration index production builds, so Java,
Kotlin and C# static selection runs on that route too.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
operator_declaration was no function kind, so `operator+` had no node and every
call and usage in its body was attributed to the file. The resolver then published
`Vec CALLS Vec2.Vec2` from a body that belongs to a named member.
The operator is now a Method named by its token, spelled like C++'s `operator+`,
through the one resolver the def side and the call scope share. Overloads merge
into one node with variants, as other C# methods do.
RED: mkc_c2_csharp_operator_plus reported scope=Vec for the constructor call. The
binary operator site `a + b` still abstains, and conversion operators, property
accessors and indexers still have no node of their own.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Rows written before the language rules existed. Each was re-derived from its
fixture source:
- Java, Kotlin, C#, Scala, Swift: a constructor call with no constructor node
binds the class, marked as a class call. Rows expecting a Method or nothing are
now required rows on the class declaration.
- Field initializers run in no callable node. The file-level node is their scope,
so the LRP oracle accepts a 0/0 range for a row naming that node, as rq_target
already does.
- Go struct literal: the type name is both USAGE and USES_TYPE at both of its
sites, and a literal key names a field.
- Recovered receiver and fluent rows in those scenarios become required.
- probe_kotlin_data_class and probe_cs_class_methods pinned both rows missing,
though both are required and found.
mkc_c2_csharp_operator_plus and the new mkc_c2_csharp_operator_overloads stay red
here: a call inside a C# operator is attributed to the file. The next commit fixes
that in production.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Rows the integrated resolver now proves become required. Fixes: a Python class statement reads its bases where it stands, so a later sibling is no base; a Kotlin callable reference in an if branch stays a usage; cppcheck findings on the integrated tree, including the OO walkers keeping a stack address in the walk. Swift package entries now count the two membership facts.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A configured define's body keeps its meaning in the expanded parse, so -DAPI=Junk does not read class Junk Foo as class Foo. An ambiguous TypeScript proof is two distinct functions extraction named flat, not one merged identity. The _Thread_local pointer form now parses, so its pin says so. The module index and filtered defs allocate through the memory core. Format production files the merges left unformatted.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
C-family takes the attribute-macro parse, everything else the C# repairing parse. The Rust project model already replaced the walker in this lane's pkgmap hunk, so only build_include_path_context survives. c_variants joins the identity rule; the read-as-value-reference lookup is guarded to C-family because other lanes were measured without it.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The project model replaces the old import-context walker, keeping the JVM lane's scoping of a context failure to Rust and C-family. Rust's identity rule runs before the merged-variant rule for Rust targets. Call, usage, write and type dispatch each gain a Rust arm beside Go's.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Python and ECMAScript each own separate paths through the binding index, so conflicts are unions. BINDING_DECORATED moves to the next free bit; Python lookups pass JS_SPACE_ANY; too_early keeps the ECMAScript closure rule, and the Python-guarded deferred site may still excuse it. Commit 456bdbb30's message says about 16 wrong edges; the measured figure is 11.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
`Ops make_ops(void);` in main.c with the definition in ops.c. The goldens named the prototype, which
has no graph node, and recorded a gap, so the correct edge counted as a false positive. A prototype
declares the external name, and the one definition of that name is the target.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Union with the other lanes. Merged same-kind declarations are one graph identity in core-go's rule; JVM overloads and TypeScript merged value/type stay on their own paths, and the JavaScript span rule still applies only to a source in this file. Evidence writing keeps the perf-scale writer, proven edge-identical. The lane's commit d38554e3d is labelled WIP but its code is final; the label could not be amended.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Conflicts are unions: the JVM lane's overload_set covers Java, Kotlin and C#, and the merged-target and Class-callable rules here cover TypeScript, JavaScript, Vue and Svelte.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Each of these pinned an abstention as a known gap, and the 18:41 run reported the exact expected
target as found. 20 field rows in c_member_fields_quality, cpp.enum.green and the four C++ static
factory rows become required.
Nine rows are new: parameter types and reads the rules now bind, read against the fixture source
one by one. `int use_beta(Beta b)` uses Beta. `a->count` in a function inside a preprocessor branch
reads Alpha.count. `g_alpha.count` on a static of written type reads Alpha.count.
In the conditional variant tests the calls in both branches and the call to `pick` now bind. A
caller's target is the one node both branches share, whose stored span is the last branch, so the
golden names that declaration.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Two failures from the 18:41 test run.
clsp_issue1527_long_binary_chain_is_not_nesting overflowed the stack under ASan. The new member
and value rules added locals to c_resolve_calls_in_node_inner, which is in every frame of a walk up
to C_LSP_MAX_WALK_DEPTH deep. What one node does now sits in a separate function kept out of line,
and it returns before the walk goes into the children. No logic changed: redis, neovim and the LLVM
subset give the same edge counts before and after.
extract_cpp_export_macro_explicit_define_priority_issue1989 pins that a define the caller provided
wins. A word the caller defined is no longer left out of the raw parse.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>