Commit Graph
2337 Commits
Author SHA1 Message Date
Wolfgang Klinger 5fd9e4f33c fix(php): drop the name guess when the receiver's class is not indexed
When the PHP LSP knows a receiver's class but the class is not in the
index, it emits php_method_typed_unindexed at 0.55, below the LSP
confidence floor. The resolver skipped that row and the weak short-name
fallback bound the call to a same-named project method: `$file->getUid()`
on a vendor File became a CALLS edge to App\Item::getUid.

#2520 turns this row into php_external_receiver when a vendor `use`
proves the class external, but two cases still reach the fallback. A
global function import (`use function sprintf;`) leaves the file's import
bindings unproven, since #2705 proves only class imports absent. And a
vendor type that arrives through a return type
(`$repository->findFile()->getUid()`) has no `use` in the calling file
at all.

Both resolvers now drop a unique_name or suffix_match edge when the LSP
row names a receiver class that no project class-like symbol shares by
simple name. A project class with that name keeps the fallback, because
the PHP LSP does not follow every cross-file type.

The test pair covers both cases, through pass_calls.c and pass_parallel.c.
Each case is RED on main on its own (vendorCall, chainedVendorCall);
calls on a project-typed receiver and on $this still resolve. On a
211-file TYPO3 project PHP CALLS edges go from 1083 to 1059
(-18 suffix_match, -6 unique_name; typed php_* edges unchanged): 25
removed, and 1 that a removed edge on the same caller had absorbed.

Signed-off-by: Wolfgang Klinger <wolfgang@wazum.com>
2026-10-19 10:21:28 +02:00
Martin Vogel d4980ad757 Merge pull request #2705 from DeusData/fix/php-global-use-known-absent
fix(php): prove an unaliased global class use absent from the project
2026-10-19 07:44:57 +02:00
Martin Vogel f26da1aaf2 Merge pull request #2688 from DeusData/fix/issue-1692-aspnet-routes-v2
fix(routes): extract ASP.NET Core attribute routes (#1692)
2026-10-19 07:43:12 +02:00
Martin Vogel 0f6cc06ba2 Merge pull request #2704 from DeusData/fix/py-namespace-reexports-v2
fix(python): resolve names re-exported through package namespaces
2026-10-19 07:20:14 +02:00
Martin Vogel 684dcf5447 Merge pull request #2703 from DeusData/fix/go-lsp-multi-return
fix(go-lsp): type variables bound by cross-file multi-value and named results
2026-10-19 06:11:30 +02:00
Martin Vogel 41232687dd Merge pull request #2691 from DeusData/fix/py-nested-class-qn-v3
fix(python): walk a class nested in a class under its outer class
2026-10-19 06:11:17 +02:00
Martin Vogel 4ae1909223 Merge remote-tracking branch 'origin/main' into fix/php-global-use-known-absent
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 05:47:30 +02:00
Martin Vogel 67e53d0ead Merge origin/main into fix/py-namespace-reexports-v2 (pick up #2697)
py_lsp.c: #2697 moved py_lookup_attribute below the C3 code (own members, C3 order, then the depth-first walk) and declares it up front; the trivial definition this branch still carried next to its module-member lookup is dropped, the module-member block is kept, and the C3 section takes main's header.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 05:07:32 +02:00
Martin Vogel 27c330324d Merge pull request #2697 from DeusData/fix/py-attr-c3-mro
fix(python-lsp): look attributes up along the C3 method resolution order
2026-10-19 05:06:00 +02:00
Martin Vogel 782ab752d9 Merge origin/main into fix/py-namespace-reexports-v2 (pick up #2700)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 04:47:30 +02:00
Martin Vogel e6b47a393b Merge pull request #2700 from DeusData/fix/py-type-checking-imports-v2
fix(python): resolve annotations through TYPE_CHECKING imports (#1277)
2026-10-19 04:46:55 +02:00
Martin Vogel 2cee7a12e2 Merge remote-tracking branch 'origin/main' into fix/issue-1692-aspnet-routes-v2
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 04:40:49 +02:00
Martin Vogel 4527fc731a Merge pull request #2702 from DeusData/fix/php-single-file-registry-finalize
fix(php): index the single-file LSP type registry
2026-10-19 04:37:17 +02:00
Martin Vogel 7b5e680f33 Merge origin/main into fix/py-namespace-reexports-v2 (pick up #2680, #2690, #2695, #2696)
py_lsp.c: the module-member lookup of this branch and the C3 super() lookup of #2696 were added at the same place; both are kept.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 03:59:33 +02:00
Martin Vogel 9b2ad49dbc test(python): package re-exports survive an incremental re-index
The re-export records of a package come from its namespace facts. An
incremental re-index that touches only the caller must still find them for
the unchanged packages (restored from their stored facts). Both drivers now
also run as a full index followed by an incremental re-index of app/main.py
alone, with the same expectations.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 03:38:19 +02:00
Martin Vogel bec015461c fix(go-lsp): split the raw Go result list, keep a single result raw
The first D1 change fed the Go cross-file registrar the extractor's
return_types. Those are cleaned names for type-reference edges:
clean_type_name strips `[]` and `*`. A cross-file single result `[]T`
therefore reached the registrar as `T`. `xs := pkg.Generate(); xs[0].M()`
lost its typing and fell back to a name guess. On prometheus the base
binds `sample[0].T()` to chunks.Sample.T, but the first D1 change bound
it to tsdb.T.

pass_lsp_cross.c now leaves a single result's raw text alone, as before
D1; the registrar already parses `*T` and `[]T`. Only a result LIST
`(...)` is split, at its top-level commas, into raw element types:
- `(*T, error)` -> `*T|error`;
- the named `(t *T, err error)` -> `*T|error`;
- the grouped `(a, b int)` -> `int|int`.
`chan`, `func`, `map`, `struct` and `interface` never count as result
names. A list that does not split cleanly keeps its raw text.

Tests: the D1 fixture gains three call sites, each with two same-named
decoys:
- a single slice result indexed (`xs[0].TS()`);
- a tuple with a slice element;
- grouped named results.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 03:29:05 +02:00
Martin Vogel c06465bae1 Merge pull request #2680 from DeusData/fix/py-relative-package-import
fix(python): from . import x names the importing package, not its parent
2026-10-19 03:24:43 +02:00
Martin Vogel 90d6d64c62 Merge pull request #2695 from DeusData/fix/py-class-body-sibling-base
fix(python): bind a nested class base to an earlier sibling of its class body
2026-10-19 03:24:32 +02:00
Martin Vogel c5b6f22ec6 Merge origin/main into fix/py-nested-class-qn-v3 (#2690 landed as 4a057e4e)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 02:59:41 +02:00
Martin Vogel 4a057e4ec6 Merge pull request #2690 from DeusData/fix/py-decorated-nested-class
fix(python): extract a decorated class nested in a class body
2026-10-19 02:58:42 +02:00
Martin Vogel 1501cade36 Merge origin/main into fix/py-attr-c3-mro (#2696 landed as 5dc83ac9)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 02:56:07 +02:00
Martin Vogel 9129c48f48 test(pipeline): the surface envelope probe expects codec version 3
The Python surface-envelope test (pipeline round 0) checks that the
persisted row is the versioned codec envelope by looking for the
literal "v":2. With SURFACE_CODEC_VERSION at 3, the envelope reads
"v":3. The assertion keeps its meaning (the row is the versioned
envelope and the def is present) and follows the version.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 02:55:24 +02:00
Martin Vogel 5dc83ac9fa Merge pull request #2696 from DeusData/fix/py-super-c3-mro
fix(python-lsp): resolve super() through the C3 method resolution order
2026-10-19 02:55:13 +02:00
Martin Vogel 36bce46e68 fix(go-lsp): cross-file multi-value and named results type their variables
The cross-file pass handed every registrar the raw result text of a
def (pass_lsp_cross.c: `dst->return_types = src->return_type`). The Go
registrar splits that string on '|' (go_lsp.c split_pipe_types), so it
got `(*Encoder, error)` as one piece. That piece did not parse, and a
cross-file callee with more than one result, or with a named result
`(e *Encoder)`, had no usable return type. As a result,
`e, err := enc.NewEncoder()`, `h, _ := newHead()` and
`_, d := diag.Run()` all left the variable untyped, and calls on it fell
to name guesses. Same-file calls were fine, because they read the AST.

Go defs now pass the parsed result list (extract_go_multi_return),
'|'-joined: `*Encoder|error`, and `*Encoder` for the named result. Other
languages keep the single raw string.

The persisted LSP surface carries this string, so SURFACE_CODEC_VERSION
goes from 2 to 3: existing caches re-extract Go surfaces once. The
literal version-2 surfaces in the codec tests move to 3, so that they
keep testing the envelope rule they name rather than the version
mismatch.

Tests: pipeline_go_multi_return_receiver_is_typed (+_parallel). A tuple
result, a named result, a tuple-bound local reached through a field,
and a named slice type each must bind the right method with an lsp_*
strategy and none of its two same-named decoys.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 02:54:41 +02:00
Martin Vogel a7f24eac47 Merge remote-tracking branch 'origin/main' into fix/php-global-use-known-absent
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 02:47:12 +02:00
Martin Vogel 658639ec56 Merge pull request #2685 from DeusData/fix/rust-generic-impl-call-scope
fix(rust): generic impl methods source their own calls (#763 Rust share)
2026-10-19 01:42:18 +02:00
Martin Vogel 4641e16d23 Merge remote-tracking branch 'origin/main' into fix/php-single-file-registry-finalize
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 01:40:56 +02:00
Martin Vogel 7c3f50605b fix(python): give the alternative-branch shadow a valid reason
A namespace fact stream is checked by cbm_py_namespace_facts_valid, which
accepts a shadow only for the value, decorated, unproven-class and
unsupported reasons. The withdrawn TYPE_CHECKING re-export carried the
compound reason, so the whole stream was rejected and the package published
no names at all (a lazy-module package lost its TYPE_CHECKING exports). It
now carries the unsupported reason: the builder cannot tell which source the
name has at runtime. python_namespace_facts_type_checking_alternatives pins
both shapes as complete, valid streams.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 01:38:03 +02:00
Martin Vogel 16b2e940bf Merge remote-tracking branch 'origin/main' into fix/issue-1692-aspnet-routes-v2
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 01:37:30 +02:00
Martin Vogel eb9594d35c test(python): name the re-export call that fails
The re-export test checks a table of calls in one loop; a failure only
reported the assertion line. Each failing call is now named, with its
venue.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 01:24:42 +02:00
Martin Vogel ea5c1f7250 Merge pull request #2689 from DeusData/fix/data-flows-every-caller
fix(pipeline): DATA_FLOWS link every caller and handler of a route
2026-10-19 01:20:34 +02:00
Martin Vogel 45b7279f6a fix(php): index the single-file LSP type registry
cbm_run_php_lsp never finalized its type registry, so every lookup during
single-file resolution scanned the stdlib plus every definition of the
file linearly: O(lookups x definitions), quadratic in the size of one
file. The cross-file path already indexes its registry.

The registry is now finalized with first-registered semantics (the first
registration of a duplicate QN wins), which keeps exactly the answers of
the linear scan, and re-indexed once after trait flattening adds methods.
The index lives in a scratch arena that dies with the call.

A test-only work ceiling (CBM_LSP_WORK_CEILING_HIT, seam builds only) lets
the work-counter test stop a reverted, unbounded loop deterministically
instead of hanging the runner; product builds have no ceiling.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 01:03:15 +02:00
Martin Vogel fe2fbad2c4 test(python): TYPE_CHECKING shapes of a package namespace
A lazy-module package publishes its names only under `if TYPE_CHECKING:`
(the else branch installs the lazy module): `lz.Lazy()` resolves to the
re-exported class. The compat shape imports a name under TYPE_CHECKING and
again in `else: try:`: the runtime binding comes from the else branch, so
`cmp.Shim()` must not reach the TYPE_CHECKING-side class.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 00:55:19 +02:00
Martin Vogel 3e9db97456 test(python): calls through package re-exports resolve by the LSP
A package __init__.py re-exports its submodules' names (explicit, star,
`__all__`-restricted, renamed, chained through a subpackage, cyclic stars,
the django `from .fields import *` shape) and callers reach them as module
attributes (`pkg.Explicit()`) or through `from pkg import Name`. Each call
must resolve by an lsp_* strategy to the re-exported definition. Names a
star does not export (`__all__`-unlisted, private), a re-export the module
shadows later, and one before a whole-namespace barrier must not. Plain
from-imports of the defining module are the control. Both venues.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 00:50:31 +02:00
Martin Vogel a45f36251e test(python): a name the else branch rebinds is no TYPE_CHECKING-only import (#1277)
The airflow compat shape imports a name under `if TYPE_CHECKING:` and again
in the else branch, usually inside try/except ImportError: the name is bound
at runtime, so its TYPE_CHECKING import is not annotation-only and must stay
unrecorded, as the runtime import itself does. A star import in an elif or
else branch may bind any name. A pure annotation import stays flagged.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-19 00:20:06 +02:00
Martin Vogel 7cb58d3f15 Merge remote-tracking branch 'origin/main' into fix/php-global-use-known-absent
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 23:58:22 +02:00
Martin Vogel 88bfceda0b Merge remote-tracking branch 'origin/main' into fix/issue-1692-aspnet-routes-v2
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 23:57:12 +02:00
Martin Vogel 1a7839db2e Merge pull request #2687 from DeusData/fix/def-props-buffer-every-field
fix(pipeline): size definition properties for every field
2026-10-18 23:56:35 +02:00
Martin Vogel 257aea1379 test(python): annotations resolve through TYPE_CHECKING imports (#1277)
The second half of #1277: the reporter's typed-field chain with both
annotation imports under `if TYPE_CHECKING:` (the usual shape when the
import would cycle), through `typing.TYPE_CHECKING` too. The call resolves
by the LSP as with runtime imports, and a runtime call through a
TYPE_CHECKING-only name gets no CALLS edge at all. The extraction test reads
the new CBMImport.type_checking_only flag, declared here and not yet set.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 23:49:29 +02:00
Martin Vogel edaefefadf test(python): attribute lookup follows the C3 method resolution order
The radarr diamond seen from an ordinary attribute: self.write_state() in
RadarrCalendarEntity and e.write_state() on a RadarrCalendarEntity look the
method up along the class's C3 order, which reaches CalendarEntity before
the shared base Entity. Single inheritance as the control; sequential and
parallel.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 23:23:17 +02:00
Martin Vogel 29e7832c04 test(python): super() follows the C3 method resolution order
The home-assistant radarr shape: RadarrCalendarEntity(RadarrEntity,
CalendarEntity) where RadarrEntity reaches the common base Entity through
CoordinatorEntity and CalendarEntity overrides Entity. In C3 order a common
base comes after every class deriving from it, so super().write_state() and
super().__init__() reach CalendarEntity, not Entity through the first base's
ancestry. Single inheritance as the control; sequential and parallel.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 22:53:00 +02:00
Martin Vogel 9054309fee test(python): import the exc module in the class-body base fixture
sqlalchemy's asyncpg adapter imports its exc module; once that import
resolves, name guesses prefer exc's same-named classes over the earlier
sibling of the class body. The fixture now imports exc as a module too.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 21:58:45 +02:00
Martin Vogel e475115436 test(python): a nested class base names an earlier sibling of its class body
The sqlalchemy asyncpg adapter re-declares the DBAPI exception hierarchy as
classes nested in one class body, each based on an earlier sibling spelled
bare (class IntegrityError(DatabaseError)). Python evaluates the bases in the
enclosing class body, so the sibling wins over same-named module classes and
over another adapter's nested namesakes; a sibling defined later is not bound
yet. Sequential and parallel pipeline, each followed by an incremental
re-index.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 21:54:08 +02:00
Martin Vogel 757881619f Merge fix/py-decorated-nested-class into fix/py-nested-class-qn-v3 (F11a with origin/main 1346ac4e)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 21:46:18 +02:00
Martin Vogel dcb6d49c8f Merge origin/main into fix/py-decorated-nested-class (#2686 landed as 1346ac4e)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 21:45:00 +02:00
Martin Vogel 166167384d Merge remote-tracking branch 'origin/main' into fix/rust-generic-impl-call-scope
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>

# Conflicts:
#	tests/test_pipeline.c
2026-10-18 21:42:15 +02:00
Martin Vogel 1346ac4ea2 Merge pull request #2686 from DeusData/fix/issue-1548-python-nested-defs-v2
fix(python): extract defs nested in a function body and resolve bare names lexically (#1548)
2026-10-18 21:40:25 +02:00
Martin Vogel 08ee95a82b Merge pull request #2681 from DeusData/fix/rust-registry-rust-defs-only
fix(rust-lsp): Rust calls never bind definitions of other languages
2026-10-18 21:39:55 +02:00
Martin Vogel c6eab65ae5 Merge fix/issue-1548-python-nested-defs-v2 into fix/py-decorated-nested-class (pick up ef90708e: origin/main incl. the Smart CI selection fix #2684)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 21:34:16 +02:00
Martin Vogel 5cc7b5c757 fix(php): prove an unaliased global class use absent from the project
A PHP file's import evidence is written as complete only when every `use`
either resolved or is proven absent. A global-namespace class use such as
`use Exception;` had no absence proof, so one such line left the whole
file's bindings unknown, and its project imports reached the PHP LSP as
File QNs again (the #2520 path).

An unaliased global class use is now proven absent when no PHP file
declares a class-like symbol of that name (Class, Interface, Trait, Enum,
File or Module; namespaced ones included, so the proof stays
conservative). Aliased global uses keep the old, unknown verdict.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-18 21:16:39 +02:00