1075 Commits
Author SHA1 Message Date
Martin Vogel dedd429215 Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-03 18:09:19 +01:00
Martin Vogel 08b84e4011 Merge origin/main into fix/php-inline-html-2000
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-03 01:40:29 +01:00
Martin Vogel 8ae04f4bd1 Merge pull request #2424 from mvanhorn/fix/1642-python-constructor-calls-init
fix(python): resolve ClassName() calls to __init__
2026-11-03 01:17:11 +01:00
Martin Vogel 6d5cb97b6f Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-02 22:00:45 +01:00
Martin Vogel e87a9ff47e Merge origin/main into fix/1642-python-constructor-calls-init
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-02 18:51:12 +01:00
Martin Vogel a508219299 Merge origin/main into feat/ruby-lsp-per-file
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-02 18:09:59 +01:00
Martin Vogel ff74ab0982 Merge origin/main into fix/php-inline-html-2000
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-02 18:09:51 +01:00
Martin Vogel b2edaef43c Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-02 02:38:00 +01:00
Martin Vogel e8cb85cf0f Merge origin/main into fix/php-inline-html-2000
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 21:30:01 +01:00
Martin Vogel 054719044a fix(python): bind ClassName() only to the class own __init__
A construction call now resolves to __init__ only when the called
class declares that __init__ itself. An inherited __init__ is no
longer followed: class B(A) without its own __init__ keeps the B()
call on the Class B, as it was before this branch.

Following the bases bound every subclass construction to the base
constructor. On a django index (fb113765) that made Model.__init__
a 583-caller hub (every model instantiation), bound IntegerField()
to Field.__init__ and HttpResponseForbidden() to
HttpResponse.__init__, and degraded 625 constructor call sites
versus main (457 fell back to textual resolution, 168 lost their
row; CALLS -161). With own __init__ only, 6016 sites move to the
class own __init__, 5468 stay on the Class, none fall back to a
textual strategy, and total CALLS is +4 versus main.

Tests: the same-file and cross-file inherited cases now pin the
Class target, and a new same-file subclass test at the LSP and the
graph level covers B(A) without __init__ (stays on B, never
A.__init__) and C(A) with its own __init__ (binds to C.__init__,
never the class C or A.__init__). The strategy inventory comment in
the repro suite is updated to match.

Refs #1642

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 21:29:22 +01:00
Martin Vogel 360ab15cdb Merge origin/main into feat/ruby-lsp-per-file
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 21:18:25 +01:00
Martin Vogel 435baf6bd8 fix(ruby-lsp): survive allocation failure in the stdlib seed
The REG_* macros wrote through the return-type vector without checking
the allocation, and registered entries whose formatted QN came back NULL.
A shared ruby_seed_signature helper now leaves a failed vector out, so the
signature types as unknown (the fallback ruby_register_method already
uses), and REG_METHOD / REG_SMETHOD skip an entry whose formatted name is
NULL, since a NULL QN would reach strcmp in finalize and in every lookup.

rubylsp_stdlib_seed_survives_alloc_failure seeds a registry from an arena
that cannot allocate. Before: UBSan reported a store to a null pointer and
the run crashed with SEGV at ruby_stdlib_data.c:163. After: every
registered entry carries a name, the registry finalizes, and the Kernel
built-ins with literal names still resolve.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 21:17:28 +01:00
Martin Vogel 214a9ac843 fix(ruby-lsp): build constant paths in one pass
ruby_const_path recursed once per :: segment and re-formatted the growing
prefix at every level, so an A::B::C path cost one stack frame per segment
and quadratic bytes in the per-file arena. It now follows the scope fields
in a loop: one pass measures the segments, a second copies them right to
left into a single buffer. The result is the same string as before,
including a leading ::Foo and a scope that is not a constant path.

rubylsp_const_path_is_linear pins the arena bytes for an 800 vs a 1,600
segment path (before: 494,520 -> 1,660,520 bytes already at 400 -> 800
segments; after: 136,248 -> 150,848 at 800 -> 1,600) and the exact class
QN for a five-level path and for a rooted ::Top::Inner.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 21:17:28 +01:00
Martin Vogel 0210ea9794 fix(ruby-lsp): search each ancestor once per method lookup
The mixin walk recursed into prepend and include at every level with only
the depth cap of 16 as a bound, so a module that both prepends and
includes the next one doubled the paths per level: a miss on a chain of n
such modules cost 2^n visits (measured 4 -> 20,744 for n = 2..14).

Each lookup is now one walk that carries the fail-closed blocked flag and
a visit stamp. Ruby linearizes ancestors, so a module reached a second
time in one walk was already searched and missed (a hit or a block would
have ended the walk); skipping the repeat keeps every lookup linear in the
ancestors the file declares. Lookup order, hits and the fail-closed rules
are unchanged. The stamps live on the per-file class table, so the walk
allocates nothing.

The walk entries feed CBM_LSP_WORK (seam builds only; product builds
compile it to nothing). rubylsp_mixin_walk_visits_each_module_once pins
linear work for the doubled chain on the instance and the class side
(before: 66 -> 4,098 visits for n = 6 -> 12; after: 14 -> 26) and keeps a
diamond and a prepend-plus-include pair resolving exactly once.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 21:17:21 +01:00
Matt Van Horn 1b64c50c54 fix(python): resolve ClassName() calls to __init__
A Python construction call resolved to the Class node, so a user
__init__ never received a caller from ClassName(...) and the dead-code
view reported live constructors as unreferenced.

When the called name is the class itself, resolve it to the __init__
found on the class or, depth-first, its declared bases (the lookup
super().__init__() already uses), with a new lsp_constructor_init
strategy that joins the textual call site through its reason. Classes
with no user __init__ keep the Class target (lsp_constructor), as does
a builtins.* __init__. Calls through an instance (f = Foo(); f()) are
unchanged, since they dispatch to __call__.

This changes the documented Class-target contract for classes that
define __init__; the three tests that pinned it are updated.

Refs #1642

Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-11-01 09:11:36 -08:00
Petteri Ponsimaa 6e54ac3ce7 Merge origin/main into feat/nextjs-app-router-routes
Main took semantic index version 12 for its Markdown section change, so
the Next.js App Router routes move to version 13 with their own history
entry. pipeline_nextjs_semantic_upgrade_issue759 now starts from a
version-12 index.

Signed-off-by: Petteri Ponsimaa <petterip@gmail.com>
2026-11-01 17:19:23 +02:00
Martin Vogel f159b4c21d Merge pull request #1731 from henry-hz/upstream-pr/elixir-complexity
fix(elixir): functions carry no complexity, fingerprint or line count
2026-11-01 09:04:28 +01:00
Martin Vogel 6e0c59f5cf Merge pull request #2867 from DeusData/fix/cs-lsp-nested-types-global-ns
fix(cs-lsp): resolve nested types through type qualifiers, bind global-namespace types
2026-11-01 02:50:53 +01:00
Martin Vogel 21c253ff63 fix(cs-lsp): never pool global-namespace types as partial twins
cs_lookup_method searches the other declarations of a type (same simple
name, same declared namespace: `partial` pieces, reference-assembly
copies) before it walks the base classes. With global-namespace types now
carrying the namespace "", every same-name type declared without a
namespace anywhere in the repository became a twin of every other one.
Across a repository that is a different type per assembly (each test
project has its own Program or Helper), so a member missing on the
receiver bound to an unrelated type ahead of the receiver's own base.

cs_namespace_twins returns no twins for a type in the global namespace.

Test: cs_lsp::cslsp_global_namespace_types_are_not_partial_twins runs the
production Tier-2 C# registry builder over cross-file defs: two unrelated
global Helper types and a base class. RED without the guard:
stop_base=0 stop_unrelated_global_twin=1. GREEN with it.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 01:13:02 +01:00
Martin Vogel dad89184cb fix(cs-lsp): look up the global namespace in C# spec order
C# looks a simple type name up namespace by namespace, innermost outward.
At each namespace N it checks the members of N, then the usings of the
namespace declaration enclosing the reference. The global namespace is
the last N, and its declaration is the compilation unit. So a type
declared without a namespace hides a type that only a compilation-unit
`using` imports, while a `using` inside a namespace body still wins over
the global namespace. Step 8b used to rank every using before the global
namespace.

- CBMCSUsing records whether a directive sits inside a namespace body
  (in_namespace). cs_collect_imports tracks it per node, including the
  compilation-unit siblings after a file-scoped namespace; the cross-file
  entry pre-loads the pipeline import list without placement and the AST
  walk upgrades it.
- cs_visible_namespaces ranks a simple name as: enclosing namespaces
  innermost outward, namespace-body usings, the global namespace "", and
  last the compilation-unit usings.

Ranking the global namespace that high also requires that only a type
proven global claims it. The vendored grammar does not parse a
`ref partial struct` with members, and error recovery dissolves the
enclosing namespace, so every type after it in that namespace surfaced
with no namespace. Mapped to "" those types outranked the real, imported
declaration: on dotnet/runtime 5,313 CALLS moved from implementation
files into reference assemblies (System.Runtime.cs, which declares
DefaultInterpolatedStringHandler as a `ref partial struct`).
cs_type_decl_namespace now returns "" only when the compilation unit
parsed without errors and NULL (unknown, invisible to step 8b, as on
main) otherwise; cs_top_level_namespace passes that through.

Tests:
- parallel_csharp_nested_type_and_global_namespace_binding: the
  compilation-unit `using` probe now expects the global type (spec), and
  a new namespace-body `using` probe expects the imported one. RED with
  the previous order: cu_using=0/0.
- parallel_csharp_parse_damaged_namespace_is_not_global (sequential and
  parallel). RED without the clean-parse rule: real=0 no_damaged=0 on
  both paths.
- cs_lsp::cslsp_decl_namespace_global_needs_clean_parse: extractor
  contract ("" for a clean global type, the namespace when found, never
  "" after a parse error).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 01:12:46 +01:00
Martin Vogel bc44de15d3 fix(cs-lsp): bound the nested-type qualifier walk
Resolving a qualified type name A.B that no namespace binds now resolves
the qualifier A as a type first (nested types). A using alias whose target
is qualified by the alias itself re-enters that walk through the alias
step without end: `using Loop = Loop.Inner;` resolves Loop to the target
Loop.Inner, whose qualifier is Loop again, and a mutual pair (`using
Ping = Pong.Inner; using Pong = Ping.Inner;`) cycles the same way. Both
are legal C# when namespaces of those names exist, and the walk overflowed
the stack on them.

The walk now carries a depth counter in the per-file context and stops
after CS_QUALIFIER_MAX_DEPTH (8) levels. One level is one type-nesting
step: a namespace-qualified top-level type binds without recursing, so
real nesting stays far below the bound.

Test: cs_lsp::cslsp_cyclic_alias_qualifier_terminates (self and mutual
alias cycles; the file must still resolve Svc.Go). RED without the bound:
AddressSanitizer stack-overflow, exit 134. GREEN with it.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 01:07:37 +01:00
Martin VogelandErsin Tarhan c0a8ed8b93 fix(cs-lsp): resolve nested types through type qualifiers, bind global-ns types
Follow-up to #2347 (issue #2120). Step 8b binds same-name TOP-LEVEL types
by declared namespace, but two shapes still fell through to the short-name
fallback, where the prefix score against a path-derived QN is 0 for every
variant and registration order decided:

1. A qualified A.B whose qualifier A is a TYPE, not a namespace:
   new Command.Result(...) and new Grain.Handler(dep).Handle(...).
   cs_visible_namespaces only tried A as a namespace, and nested types
   carry no namespace_qn, so the scan never had a candidate. Resolution
   now falls back to resolving the qualifier as a type (recursively, one
   segment shorter) and binding the nested member through the registry.

2. A top-level type with no namespace declaration (global namespace):
   cs_top_level_namespace returned NULL for it, making it invisible to
   step 8b. Top-level C# types now register namespace_qn "" and
   cs_visible_namespaces appends the global namespace last.

Test: parallel_csharp_nested_type_and_global_namespace_binding covers a
nested-type constructor and the member call on its result, a chained
constructor receiver, and a same-name type split across the global
namespace and an imported namespace, in the sequential pipeline and in
the parallel pipeline with the production Tier-2 C# registry. Decoys are
registered first. Adapted to current main: the two constructor-edge
checks gate the parallel path only, because the sequential constructor
edge is still drawn by the textual constructor carrier, a layer this
change does not touch.

Distilled from #2401: the net change of commits d11be54f and 613060ea.
The temporary debug prints added in d11be54f and the stale copy of #2347
the branch carried (already on main as 50d19f85) are not taken.

Co-authored-by: Ersin Tarhan <ersintarhan@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 01:07:01 +01:00
Martin Vogel 176991c036 Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-11-01 00:05:24 +01:00
Martin Vogel 812d0755c1 Merge pull request #2854 from divakantpandey/fix/2768-angular-http-client-method
fix(pipeline): infer HTTP method for Angular and verb-suffix client calls (#2768)
2026-10-31 23:47:50 +01:00
Martin Vogel 3b33babd7c style(elixir): put the definition comment back above extract_elixir_func_def
The complexity helpers were inserted between the comment that documents
extract_elixir_func_def and the function itself, so that comment read as
the description of elixir_node_text_is. Move it back above the function it
documents; the comment and signature are again byte-identical to main. No
code change.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 21:31:39 +01:00
Martin Vogel 2caf51a4c6 fix(elixir): a folded multi-clause function carries the metrics of every clause
Since #2371 the clauses of a multi-clause function fold into one Function
node whose span covers all of them, but only the first clause was measured:
the folded node kept the complexity, cognitive, loop and access metrics and
the line count of that clause while its span grew.

fold_elixir_clause now receives the metrics of each clause it folds and
adds them to the node: cyclomatic, cognitive and loop_count add up,
loop_depth and max_access_depth take the deepest clause, every clause past
the first adds one dispatch decision to cyclomatic, and lines is recomputed
from the folded span. A clause whose walk reports
CBM_WALK_METRIC_UNAVAILABLE makes the folded value unavailable rather than a
partial sum. This is the treatment proposed in the PR description and
agreed in the review thread.

Indexed elixir-lang/elixir (669f8481, 6703 Elixir Function nodes) against
the merge parent: the 2212 folded functions change, the 4491 single-clause
functions keep identical metrics, Functions with complexity above 0 go from
3412 to 4785, and every node now has lines equal to its span (4491 did
before).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 21:31:23 +01:00
Martin Vogel aa3161fd81 fix(elixir): grow the complexity walk stack instead of capping it
elixir_compute_complexity kept its pending frames in one fixed 4096-entry
array (48 bytes each, 196,608 bytes in a single stack frame) and stopped
pushing children once it was full. Children are pushed last to first, so a
wider body lost its FIRST children and the function reported a lower
complexity with no signal, on exactly the largest functions. Worker threads
do not get the 8 MB main-thread stack, so the array was a risk of its own.

It now uses the walker pattern cbm_compute_complexity has used since #2375:
a 512-frame on-stack first chunk that spills to the heap through
cbm_walk_stack_reserve (memory core, class EXTRACT) and is released with
cbm_walk_stack_release. If the stack cannot grow, every metric reports
CBM_WALK_METRIC_UNAVAILABLE instead of an undercount. This answers items 2
and 3 of the 2026-08-20 review.

The new test builds a 5000-statement body of alternating if and for. The
fixed stack reports complexity 4095 for it instead of 5000.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 21:31:06 +01:00
Martin Vogel 22a7dff3ff fix(service-patterns): end the Angular receiver rows at a separator (#2768)
The new HttpClient receiver rows matched by prefix, and an uppercase
letter after an id counts as CamelCase glue, so "this.http" also matched
this.httpAdapter.get (a NestJS route registration) and this.httpServer.post,
and "$http" matched $httpBackend.expectGET (an AngularJS test double).

Each receiver row now ends in a dot, like "gin.", plus a line-break twin
(LF, and CR for CRLF files): a chain wrapped before the verb keeps the break
in its callee text ("this.http\n      .post"). On
gothinkster/angular-realworld-example-app 5 of the 18 client calls are
written that way; with dot-only rows they fell back to phantom route
registrations. "HttpClient" duplicated the Java/C# row and
"this.httpClient." is covered by "httpClient.".

Unit cases pin both directions, and the Angular pipeline test gains a
wrapped call on both resolver routes.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 20:59:40 +01:00
Martin Vogel 2e6ab84fd9 Merge origin/main into the Elixir complexity branch
Brings the branch up to f6fb3e0d, which carries #2371 (guarded def heads,
the multi-clause fold and typespec attributes) and #1730.

Two files conflicted, both at spots where main rewrote the Elixir
definition code. Each is rebuilt as the main version of the file plus the
lines this branch adds, at the same place; no conflict side is
concatenated:

- internal/cbm/extract_defs.c: the complexity helpers sit between the
  definition comment and extract_elixir_func_def as before, and the
  metrics plus fingerprint block follows def.is_exported in the unfolded
  path.
- tests/test_extraction.c: TEST(elixir_complexity_and_fingerprint) and
  its RUN_TEST go just before the Haskell block, after the Elixir tests
  main added.

Per-file patch-id (git diff -U0 | git patch-id --stable) of this merge
against origin/main equals the branch change against its old base:
extract_defs.c b591a7bc, test_extraction.c 7b507156. The merge removes no
line of either file.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 20:56:13 +01:00
Martin Vogel a5c5b42fea Merge origin/main into fix/elixir-extraction-defects
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 16:38:55 +01:00
Martin Vogel 2e8865c8d0 Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 16:38:48 +01:00
Martin Vogel 747665d71f Merge pull request #2752 from gaurav0107/fix/2537-go-net-http-servemux-patterns-with-a-met
fix(routes): read Go 1.22 ServeMux method and host patterns
2026-10-31 13:53:35 +01:00
Divakant Pandey c548d8e46a fix(pipeline): infer HTTP method for Angular and verb-suffix client calls (#2768)
Signed-off-by: Divakant Pandey <divakant01@gmail.com>
2026-10-31 14:16:04 +05:30
Martin Vogel c0e929378a Merge origin/main into fix/elixir-extraction-defects
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 06:11:38 +01:00
Martin Vogel 3e075d59be Merge origin/main into fix/2537-go-net-http-servemux-patterns-with-a-met
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 06:11:15 +01:00
Martin Vogel f6100d905e Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 06:10:54 +01:00
Martin Vogel 8c62cb3344 Merge origin/main into fix/go-init-qn
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-31 06:10:26 +01:00
Martin Vogel 9f0fdcb400 Merge pull request #2613 from bline/fix/doc-section-hierarchy
fix(markdown): qualify a repeated heading's Section by its parent headings (#2586)
2026-10-31 06:09:28 +01:00
Martin Vogel 76dda7e35b Merge pull request #2827 from nefayran/fix/2818-puml-edge-operand
fix(diagram): set an empty PlantUML operand id when there is none
2026-10-31 04:27:30 +01:00
Martin Vogel bdf204b2e5 Merge origin/main into fix/elixir-extraction-defects
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-30 22:48:50 +01:00
Martin Vogel 0bd442cd2f Merge origin/main into fix/doc-section-hierarchy
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-30 22:34:08 +01:00
Martin Vogel 7ee29d8841 Merge origin/main into fix/go-init-qn
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-30 22:33:54 +01:00
Martin Vogel 46c95bcddb Merge origin/main into fix/2537-go-net-http-servemux-patterns-with-a-met
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-30 22:29:48 +01:00
Martin Vogel ca1f750469 Merge origin/main into fix/swift-init-extraction
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-30 22:29:33 +01:00
Martin Vogel a33878c039 Merge pull request #2420 from Fieldnote-Echo/perf/py-cross-registry-index
perf(py-lsp): O(1) type membership in the shared Python cross-registry build
2026-10-30 22:26:46 +01:00
Martin Vogel edb4a6e735 Merge pull request #2295 from MopicMP/fix/java-record-accessor-calls
fix(java): resolve record accessor calls, and never bind a call to data
2026-10-30 22:26:38 +01:00
Petteri Ponsimaa 1237096a46 Merge origin/main into feat/nextjs-app-router-routes
Main has used semantic index versions 10 and 11 since this branch took 10,
so the Next.js App Router routes move to version 12 with their own history
entry: an index main wrote at 11 rebuilds once for the new Routes.
pipeline_nextjs_semantic_upgrade_issue759 now starts from a version-11 index.
The other conflicts were tests both sides added at the same place; both kept.

Signed-off-by: Petteri Ponsimaa <petterip@gmail.com>
2026-10-29 22:13:57 +02:00
Ben Fairless 41f27cca4b Merge branch 'main' into feat/ruby-lsp-per-file 2026-10-29 15:53:17 +08:00
Martin Vogel f925afaab7 Merge origin/main into fix/elixir-extraction-defects
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-29 06:32:58 +01:00
Martin Vogel d807b1eca7 Merge pull request #2419 from Fieldnote-Echo/perf/py-lexical-ancestor-kind
perf(python): climb the walk cursor for scope-directive and default checks
2026-10-29 06:32:06 +01:00