Commit graph

77 commits

Author SHA1 Message Date
Gergo Magyar
cb1293b718 fix(python): route module aliases directly to moduleAliasMap in import processor
`import models as m` aliases were stored in namedImportMap (a symbol-binding
map) then cross-referenced in pipeline.ts — semantic misuse and inefficient.

Refactored: NamedBinding gains `isModuleAlias` flag. applyImportResult routes
tagged bindings directly to moduleAliasMap at import time. Removes the
pipeline.ts post-processing loop entirely.

Added test fixture and 5 integration tests for `import X as Y` with
multi-module disambiguation (both models.py and auth.py export User).
2026-03-23 09:36:33 +00:00
Shunsuke Hayashi
9f2d1780d5 fix(ingestion): resolve Python import-alias CALLS edges (#417)
`import numpy as np` and `from models import User as U` previously
generated no CALLS edges because:

1. `import_statement` with an `aliased_import` child was not captured
   by the tree-sitter query for Python imports.
2. `extractPythonNamedBindings()` only handled `import_from_statement`,
   ignoring plain `import X as Y` forms.

Changes:
- `tree-sitter-queries.ts`: add query pattern for
  `(import_statement name: (aliased_import name: (dotted_name)))` so
  the import path is captured before named-binding extraction runs.
- `named-binding-extraction.ts`: extend `extractPythonNamedBindings()`
  to handle `import_statement` nodes carrying `aliased_import` children.
  Records `{ local: "np", exported: "numpy" }` so call-sites using the
  alias resolve to the real module.
- `test/fixtures/lang-resolution/python-alias-imports/`: update fixtures
  used by `python.test.ts` to exercise `from models import User as U`.

Existing tests in `test/integration/resolvers/python.test.ts`
(suite "Python alias import resolution") cover this path.
2026-03-23 09:17:43 +00:00
Gergő Magyar
a57550815f
Merge pull request #463 from ShunsukeHayashi/fix/python-calls-zero-337
fix(python): resolve module-qualified constructor calls — 0 CALLS edges (Issue #337)
2026-03-23 08:59:21 +00:00
Gergo Magyar
bbd95457df test(python): strengthen module-import tests, un-skip match/case, add perf guard
- Rewrite Issue #337 test suite: 5 tests → 19 tests with exact node/edge
  counts, sourceFilePath guards, negative tests, method call disambiguation
  (u.save(), a.login(), v.verify()), HAS_METHOD verification, and
  cross-module collision assertions
- Un-skip 2 match/case as-pattern tests (they pass now) and remove leftover
  DEBUG test
- Add per-chunk language guard for synthesizeWildcardImportBindings — skips
  full graph traversal for TS/JS-only chunks, avoiding O(chunks × graph_size)
- Rename fixture method check → verify to avoid BUILT_IN_NAMES noise filter
- Expand fixture with method calls on constructor-inferred receivers
- Fix stale comment referencing only "Go package imports"
2026-03-23 08:25:46 +00:00
Shunsuke Hayashi
f90aabf9a8 fix(python): resolve module-qualified calls via moduleAliasMap
Previously, Python was added to WILDCARD_IMPORT_LANGUAGES which expanded
all exported symbols into namedImportMap using first-seen wins. This caused
`auth.User()` to incorrectly resolve to `models.py:User` when both modules
exported a class named User.

Root cause: Python `import models` is a namespace import, not wildcard
symbol expansion. Expanding all symbols produces ambiguous bindings that
cannot be disambiguated later.

Fix:
- Remove Python from WILDCARD_IMPORT_LANGUAGES
- Add ModuleAliasMap (callerFile → alias → sourceFile) to ResolutionContext
- In synthesizeWildcardImportBindings, build moduleAliasMap for Python
  using the filename stem as the module alias
- In resolveCallTarget, add module-alias disambiguation step: when multiple
  candidates survive filtering and the receiver name matches a module alias,
  narrow candidates to the aliased file

Result: `models.User()` → models.py:User, `auth.User()` → auth.py:User
even when both modules export a class named User.

Adds regression test for the ambiguity case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 16:33:06 +09:00
Zander Raycraft
a3fac2f672
Merge pull request #395 from zm2231/feat/http-embedding-backend 2026-03-22 21:47:53 -05:00
zm2231
9954f6fdfd fix: timeout detection, always-on dim validation, test hardening
- Fix timeout detection: AbortSignal.timeout() throws TimeoutError, not
  AbortError. Timeouts are no longer retried (30s fail, not 93s).
- Validate embedding dimensions in both httpEmbed and httpEmbedQuery
  against config.dimensions or the 384d schema default. When DIMS is
  unset, the error says 'Set GITNEXUS_EMBEDDING_DIMS=N' to guide users.
- Centralize test env var cleanup in afterEach via savedEnv snapshot.
- Test mocks use 384d vectors matching schema default.
- 4 new tests: timeout not retried, network retry success, query path
  dim mismatch, unset-dims hint. 23 total, all pass.
2026-03-22 20:21:08 -04:00
Shunsuke Hayashi
cd1c0ff7dc fix(python): resolve module-qualified constructor calls (Issue #337)
Python repos were producing 0 CALLS edges for module-qualified constructor
calls like `models.User()` where `import models` is a bare module import.

Root causes:
1. `SupportedLanguages.Python` was absent from `WILDCARD_IMPORT_LANGUAGES`,
   so `synthesizeWildcardImportBindings` never ran for Python files — bare
   module imports never received per-symbol namedImportMap bindings.

2. Synthesis only ran in the Phase 14 pre-pass, after all chunks had already
   been call-resolved. When `models.User()` was processed in Phase 3+4,
   `namedImportMap` was empty for Python → Tier 2a-named fell through to
   Tier 2a which found both `models.py:User` and `auth.py:User` (ambiguous).

3. `filterCallableCandidates` with `callForm='member'` excluded `Class` nodes
   (only `CALLABLE_SYMBOL_TYPES` = Function/Method/Constructor/…). With 2
   ambiguous Class candidates both were dropped, producing 0 CALLS edges.

Fixes:
- Add `SupportedLanguages.Python` to `WILDCARD_IMPORT_LANGUAGES` so that
  `import models` expands to per-symbol namedImportMap entries (first-seen
  semantics: `User→models.py:User`, `Admin→auth.py:Admin`).

- Call `synthesizeWildcardImportBindings` inline in the chunk loop, after
  `processImportsFromExtracted` but BEFORE `processCallsFromExtracted`. This
  ensures Tier 2a-named can disambiguate `module.ClassName()` at initial
  call-resolution time. The Phase 14 pre-pass remains as a final safety net.

- Add a fallback in `resolveCallTarget`: if `callForm='member'` yields 0
  filtered candidates, retry with `callForm='constructor'`. This handles the
  case where a module-qualified class instantiation (e.g. `models.User()`)
  is syntactically an attribute-access call but semantically a constructor
  call. The fallback only triggers for 0-candidate member calls, so it
  cannot over-eagerly promote normal member calls.

Tests: add `python-module-import` fixture (models.py/auth.py/app.py) with
4 regression tests covering IMPORTS edges, name-collision disambiguation
for `models.User()`, and `auth.Admin()`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 00:26:00 +09:00
Gergő Magyar
907440cf0b
Merge pull request #427 from ShunsukeHayashi/fix/impact-confidence-412 2026-03-22 10:11:11 +00:00
Gergő Magyar
843c561e9b
Merge pull request #425 from ShunsukeHayashi/fix/db-lock-325 2026-03-22 09:40:25 +00:00
Gergő Magyar
4c8be50cb1
Merge pull request #424 from ShunsukeHayashi/fix/lan-cors-390 2026-03-22 09:39:42 +00:00
Shunsuke Hayashi
d07a69c3b1 fix(server): allow private/LAN network origins in CORS (#390)
Allow RFC 1918 private network ranges in the CORS origin allowlist so
users running GitNexus on their home or office LAN can access the web UI
from another device on the same network.

Permitted private ranges:
  10.0.0.0/8      (10.x.x.x)
  172.16.0.0/12   (172.16.x.x – 172.31.x.x)
  192.168.0.0/16  (192.168.x.x)

The origin check is extracted into an exported isAllowedOrigin() helper
so it can be unit-tested in isolation.  A new test file covers:
  - No origin (curl / server-to-server)
  - localhost and 127.0.0.1 variants
  - All three RFC 1918 ranges including boundary values
  - The deployed gitnexus.vercel.app site
  - Public / untrusted origins that must be rejected

The server bind address (127.0.0.1 by default) is unchanged; this PR
only affects which cross-origin browser requests are accepted.

Closes #390
2026-03-22 18:28:21 +09:00
Shunsuke Hayashi
d206bf6772 fix(ingestion): calculate confidence per resolution tier for heritage/MRO edges (#412)
Instead of hardcoding confidence: 1.0, compute it at ingestion time using
the same resolution tier system that CALLS edges already use.

Heritage edges (EXTENDS, IMPLEMENTS):
- resolveHeritageId now returns { id, confidence } using TIER_CONFIDENCE
- Same-file → 0.95, import-scoped → 0.9, global → 0.5
- Edge confidence = geometric mean of source and target confidence
  (principled for partially-correlated cross-scope estimates, per
  Dillig et al. POPL 2011 and Dempster-Shafer theory)

MRO edges (OVERRIDES):
- MRO-ordered → 0.9, class method wins → 0.95
- Single interface → 0.85, ambiguous/unresolved → 0.5

IMPORTS and CONTAINS intentionally keep 1.0 (deterministic).

Closes #412
2026-03-22 18:23:40 +09:00
Shunsuke Hayashi
03156935cb fix(lbug): retry on DB lock with session-safe cleanup (#325)
When LadybugDB throws a BUSY/lock error (e.g. CLI and server running
concurrently), withLbugDb retries up to 3 times with linear backoff.

Addresses review feedback:

1. **Race condition fix**: Connection cleanup (close + state reset) now
   runs inside runWithSessionLock, preventing another operation from
   acquiring the lock between cleanup steps and having its connection
   closed from under it.

2. **Tests call withLbugDb directly**: Replaced simulateWithRetry helper
   with tests that invoke the real withLbugDb implementation, catching
   regressions in retry count, backoff, and lock interaction.

Closes #325
2026-03-22 18:21:21 +09:00
Shunsuke Hayashi
09e3609376 fix(analyze): address review — rename --no-git to --skip-git, fix stale cache
Addresses all review items from @magyargergo and Copilot:

1. **Rename --no-git to --skip-git**: Commander.js treats --no-X flags
   as negation of --X (stores as options.git = false, not options.noGit).
   --skip-git maps correctly to options.skipGit.

2. **Fix false " Already up to date\ on non-git folders**: When
 currentCommit is empty string, skip the cache check — we cannot
 detect changes without git, so always rebuild.

3. **Replace isGitRepo() with hasGitDir()**: Use filesystem check
 (statSync on .git) instead of shelling out to git CLI. Consistent,
 faster, and works when git is not installed.

4. **Fix misleading warning**: Message now only fires when .git
 directory is actually absent (not when git CLI fails).

5. **Add CLI integration tests**: Verify Commander maps --skip-git
 correctly and that non-git folders are rejected without the flag.
2026-03-22 17:40:02 +09:00
Shunsuke Hayashi
4dffd81b12 fix(analyze): allow indexing folders without a .git directory (#384)
Previously gitnexus analyze exited with an error on any directory that
lacked a .git entry, making it impossible to index generated code,
vendored libraries, or monorepo sub-trees that are not git roots.

Changes:

storage/git.ts
  - Add hasGitDir(dirPath): boolean — a lightweight synchronous check for
    the presence of a .git file or directory.  Works for git worktrees
    (.git file pointing at the real repo) as well as standard repos.

cli/analyze.ts
  - Add noGit?: boolean to AnalyzeOptions.
  - When the explicit inputPath resolves to a non-git folder (or the cwd
    is not inside any git repo), respect --no-git instead of hard-failing.
  - Print an actionable tip pointing at --no-git when git is absent and the
    flag was not supplied.
  - currentCommit defaults to an empty string for non-git folders so the
    up-to-date check still functions (empty string never matches a real
    commit hash, so the index is always rebuilt).
  - Skip addToGitignore() when no .git is present — there is nothing to
    update and the function would create a stale .gitignore at the root.

Git-dependent features that remain disabled for non-git folders:
  - Incremental update (always rebuilds from scratch)
  - Commit tracking in metadata
  - .gitignore update

Closes #384
2026-03-22 13:20:02 +09:00
Gergo Magyar
76ed0fa53b fix: address PR #409 review findings (P0-P3) and simplify import resolution API
Bug fixes (P0):
- Narrow Go /cmd/ entry-point detection to only match /main.go
- Fix Rust scoped grouped imports (use crate::models::{User, Repo}) resolution
- Filter PHP use function/use const from class-type namedImportMap bindings

Improvements (P1):
- Add C# resolveStandard fallback when .csproj discovery fails
- Change preprocessImportPath return type to string | null with caller guards
- Add Q_SIGNALS/Q_SLOTS (standard plural Qt macros)
- Fix stale "11 supported languages" comment → 13

API simplification (P2):
- Replace buildImportResolvers() factory with const importResolvers table
- Move configs onto ResolveCtx (extends ImportResolutionContext)
- Eliminate tsconfigPaths parameter threading through 6 non-TS resolvers
- Split utils.ts (1,476 lines) into ast-helpers.ts + call-analysis.ts + utils.ts
- Consolidate findChild/findChildByType into single source of truth
- Match multi-file import bindings to files by basename for namedImportMap

Cleanup (P3):
- EMPTY_INDEX returns shared frozen empty array instead of allocating per call
- Type appendKotlinWildcard parameter as SyntaxNode instead of any
- Document call-routing validation requirement on CallRouter type

Tests:
- Add unit tests for preprocessImportPath (13 tests)
- Add integration tests: Rust scoped multi-file, PHP use function/const,
  C# without .csproj, Go cmd/ helper scoring (14 tests, 4 fixtures)

All 3579 tests pass.
2026-03-21 14:15:15 +00:00
Gergo Magyar
2c17a4642c refactor: unify language dispatch with compile-time exhaustive tables
Replace the 120-line if-chain in resolveLanguageImport() and the 7-branch
dispatch in extractNamedBindings() with per-language dispatch tables using
`satisfies Record<SupportedLanguages, T>` for compile-time exhaustiveness.

Key changes:
- New import-resolution.ts: buildImportResolvers factory + namedBindingExtractors
  table + preprocessImportPath with control character rejection
- Extracted loadImportConfigs(), createImportEdgeHelpers(), getLabelFromCaptures()
  to eliminate duplication across import-processor.ts and parse-worker.ts
- Added isCppDuplicateClassFunction and getLabelFromCaptures shared helpers
- Migrated ENTRY_POINT_PATTERNS and AST_FRAMEWORK_PATTERNS_BY_LANGUAGE to
  satisfies Record<SupportedLanguages, T> with compile-time exhaustiveness
- Added Kotlin entry-point patterns (Android lifecycle, Ktor, MVVM)
- Expanded framework detection: Go (Gin/Echo/Fiber/gRPC), Rust (Actix/Axum/
  Rocket/Tokio), C++ (Qt), Swift (UIKit/SwiftUI/Vapor), Ruby (Rails/Sinatra)
- Fixed Go cmd/ entry-point detection operator precedence bug
- Added EMPTY_INDEX frozen sentinel for type-safe memory cleanup
- Unified ImportResolutionContext (suffixIndex->index, removed unused dispose())
- Extracted NamedBinding interface (replaced 16 inline occurrences)
- Replaced any with SyntaxNode on all tree-sitter node parameters
- Added contributor checklist to SupportedLanguages enum

14 files changed, +318/-550 (net -232 lines). All 3550+ tests pass.
2026-03-21 11:48:11 +00:00
Gergo Magyar
fb20a3c752 feat: implement cross-file binding propagation for multiple languages
- Enhance C++ tree-sitter queries to support inline class method declarations and return types.
- Introduce `importedRawReturnTypes` in `BuildTypeEnvOptions` for cross-file raw return type handling.
- Add `FileTypeEnvBindings` interface to capture file-scope type bindings for exported symbols.
- Implement logic in `parse-worker.ts` to extract and serialize file-scope type bindings for cross-file type resolution.
- Create test fixtures for C++, Go, Ruby, and Rust to validate cross-file binding propagation.
- Update integration tests to verify correct resolution of method calls across files for C++, Go, Ruby, and Rust.
- Document Phase 14: Cross-File Binding Propagation in the type resolution roadmap and system documentation.
2026-03-21 07:47:04 +00:00
Gergo Magyar
f1fbe643df Merge remote-tracking branch 'origin' into feat/phase14-cross-file-binding-propagation 2026-03-21 06:09:57 +00:00
zm2231
9baef90ae2 fix: edge case guards, dim mismatch hard-throw, UX label
- Guard against empty endpoint response in httpEmbedQuery (Bug 1)
- Validate response item count matches batch size in httpEmbed (Bug 2)
- Dimension mismatch now hard-throws instead of warn-and-continue (Bug 3)
- Progress bar shows Connecting to embedding endpoint in HTTP mode (UX gap)
- Added 3 tests: empty response, truncated batch, dim mismatch throw
- All 19 HTTP embedder tests pass
2026-03-20 22:27:27 -04:00
Abhigyan Patwari
1f7764c49b
fix: register Section in NODE_TABLES and NODE_SCHEMA_QUERIES (#401)
* feat: add markdown file indexing (headings + cross-links)

Parse .md/.mdx files using regex (no tree-sitter dependency) to extract:
- Section nodes from headings (h1-h6) with hierarchy via CONTAINS edges
- Cross-file IMPORTS edges from markdown links to other repo files

Ported from #286 to resolve conflicts with kuzu→lbug rename.

Co-Authored-By: Dennis Palatov <dp-web4@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add Section to NODE_TABLES and NODE_SCHEMA_QUERIES

The Section schema was defined but not registered in NODE_TABLES or
NODE_SCHEMA_QUERIES, so the table was never created in the database.
Also adds missing FROM File TO Section relation entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update schema test counts for Section node type

NODE_TABLES: 27→28, NODE_SCHEMA_QUERIES: 27→28, SCHEMA_QUERIES: 29→30

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add diagnostic output to skills-e2e idempotency test

Show stdout/stderr in assertion message so CI failures reveal
why the second analyze --skills run exits with code 1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add Section COPY query with level column in lbug-adapter

Section table has 8 columns (includes level) but getCopyQuery fell
through to the default 7-column multi-language path. Adds explicit
Section cases to getCopyQuery and insertNodeToLbug/upsertNodeToLbug.

Error was: COPY failed for Section: Number of columns mismatch. Expected 7 but got 8.

---------

Co-authored-by: Dennis Palatov <dp-web4@users.noreply.github.com>
2026-03-21 04:00:16 +05:30
Gergő Magyar
abeb52e5e5
Merge pull request #69 from x0m4ek/feat/codex-support 2026-03-20 21:22:32 +00:00
Gergo Magyar
6c972079e0 feat(type-resolution): per-language cross-file binding tests + resolver fixes
Add cross-file binding propagation integration tests for 6 languages
(Python, JavaScript, Java, PHP, C#, Kotlin) with fixture repos and
HAS_METHOD edge assertions.

Fix 3 language resolver issues uncovered by tests:
- Kotlin: class methods now labeled Method (not Function) via shared
  isKotlinClassMethod() utility; non-aliased imports create NamedImportMap
  entries; 2-segment package-directory fallback for top-level function imports
- PHP: namespace-directory fallback for use-function imports; SuffixIndex
  preferred over linear scan; path traversal rejection; PSR-4 sort cached
- JVM: root-level package path matching; indexOf→lastIndexOf for correctness

Address code review findings:
- Extract runCrossFileBindingPropagation() from 810-line pipeline function
- Replace (importCtx as any) casts with typed dispose() method
- Remove Tarjan's SCC (dev-only YAGNI, ~85 lines)
- Remove dead PARALLEL_RE_RESOLUTION_THRESHOLD constant
- Fix constructor handling divergence in getLabelFromCaptures
- Optimize gap pre-scan with early exit once threshold exceeded
- Fix findEnclosingFunction any→SyntaxNode type
2026-03-20 15:38:27 +00:00
Dmytro
cbfdae0303 test(cli): cover full Codex setup flow 2026-03-20 15:28:42 +01:00
Gergő Magyar
88e0034771
Merge pull request #396 from hiromima/fix/kuzu-concurrent-query-segfault-and-stale-data
fix: sequential enrichment queries + stale data detection (#285, #290, #292, #297)
2026-03-20 12:29:00 +00:00
hiromima
2ff4d93314 fix(test): unify staleness-and-stability into single withTestLbugDB block
All 4 test blocks now share one DB lifecycle to avoid cross-block
"Database is closed" errors caused by LadybugDB's shared global DB
in a single vitest fork. Staleness detection (which triggers closeLbug)
runs last to avoid invalidating connections for other blocks.

11/11 tests pass on macOS, Ubuntu, and Windows.
2026-03-20 21:06:30 +09:00
Gergo Magyar
fff716dd92 feat(type-resolution): Phase 14 enhancements — single-pass seeding, Tarjan's SCC, cross-file return types
E0: Fix AST cache thrashing in re-resolution loop (was creating size-1
cache per file), batch file reads per topological level, add
MAX_CROSS_FILE_REPROCESS=2000 cap for adversarial repos.

E1: seedCrossFileReceiverTypes() — enrich ExtractedCall.receiverTypeName
from ExportedTypeMap+namedImportMap in O(1) Map lookups, eliminating
re-parse for ~80-90% of single-hop cross-file receiver types.

E2: computeImportCycleSCCs() — iterative Tarjan's SCC on cycle subgraph
from Kahn's output. Dev-mode diagnostic logging of individual import
cycle components.

E3: buildImportedReturnTypes() + ReturnTypeLookup extension — cross-file
return type propagation with corrected local-first priority (SymbolTable
checked first, cross-file fallback only on 0 matches, ambiguous 2+
returns undefined).

E4: PARALLEL_RE_RESOLUTION_THRESHOLD constant, timing metrics, worker
parallelization design comments (deferred implementation).

24 new tests (6 E1 + 6 E2 + 7 E3 unit + 5 E3 integration). All 3478
tests pass.
2026-03-20 12:00:36 +00:00
Gergo Magyar
a6a1004e82 feat(type-resolution): Phase 14 — cross-file binding propagation
Add ExportedTypeMap infrastructure to propagate resolved type bindings
across file boundaries. When file A exports `const user = getUser()`
(resolved to `User`), file B importing `user` now gets seeded with
`user → User`, enabling `user.save()` to produce CALLS edges.

Key components:
- `importedBindings` option on BuildTypeEnvOptions with scopeEnv seeding
  AFTER walk() to respect first-writer-wins (local declarations win)
- `collectExportedBindings()` in call-processor using graph node
  isExported flag (no SymbolDefinition changes needed)
- Inline Kahn's algorithm topological sort with level grouping for
  parallel-safe file ordering and cycle detection
- Re-resolution pass in pipeline.ts: topological order, 3% skip
  threshold, path validation, per-file export caps (500)
- 32 new tests: 11 topological sort, 6 seeding, 15 integration
  (simple cross-file, re-export chain, circular imports)

All 3454 tests pass (32 net new, 0 regressions).
2026-03-20 09:31:20 +00:00
hiromima
5b012c3351 test: add e2e tests for stale detection, sequential enrichment, stability (#396)
- Stale data detection: verify ensureInitialized() detects meta.json
  changes and re-opens pool without SIGSEGV or WAL corruption
- Staleness throttle: verify 5s throttle window doesn't cause errors
- Sequential enrichment: impact() enrichment queries complete on arm64
- Consecutive stability: 10+ sequential cypher calls, mixed tool cycles
- Watchdog guard: parallel queries with activeQueryCount protection
- stdout restoration: verify process.stdout.write is properly restored

Covers test plan items from PR #396 (issues #285, #290, #292, #297)
2026-03-20 18:04:27 +09:00
Gergo Magyar
228c993bb7 fix(type-resolution): review fixes, sizeBefore optimization, and test coverage
Address code review findings from PR #392 senior compiler review:
- Fix Java "Yes" → "No" in optional-param-arity matrix (Java has no defaults)
- Simplify Kotlin hasDefaultValue while-as-if to direct const/if check
- Update OPTIONAL_PARAM_TYPES comment to include Ruby
- Replace per-declaration Set allocation with size-based Map iteration skip
- Add 11 unit tests for multi-declarator type association and constructorTypeMap
2026-03-20 08:45:42 +00:00
Gergo Magyar
c3a2815186 feat(type-resolution): optional parameter arity resolution
Add requiredParameterCount to SymbolDefinition and MethodSignature,
enabling range-based arity filtering in filterCallableCandidates.
Calls with omitted optional/default arguments now resolve correctly.

Supported: TS, Python, Kotlin, C#, C++, PHP, Ruby (7 languages).
Detection via OPTIONAL_PARAM_TYPES set + hasDefaultValue helper.

9 integration tests added across all 7 languages.
2026-03-20 08:14:58 +00:00
Gergo Magyar
d49c76ddc5 feat: Implement virtual dispatch and overload disambiguation enhancements
- Updated AGENTS.md and CLAUDE.md to reflect new indexing metrics.
- Enhanced call-processor.ts to support cross-file inheritance tracking and improved virtual dispatch resolution.
- Added support for TypeScript overload signatures in tree-sitter queries.
- Improved type extraction for C++, C#, and Kotlin to handle smart pointers and constructor types.
- Introduced inferLiteralType for overload disambiguation across multiple languages.
- Added tests for C++ smart pointer dispatch and Kotlin virtual dispatch scenarios.
- Updated type-resolution-roadmap.md to reflect completion of phases P.1 to P.3 and outline future work on covariant return types.
2026-03-20 07:23:14 +00:00
zm2231
7dcafb647b fix: address review feedback — timeout, retry, guards, tests
- Add AbortSignal.timeout(30s) on all fetch calls
- Add retry with backoff for 429/5xx (core: 2 retries, MCP: 1 retry)
- Guard initEmbedder() and getEmbedder() to throw in HTTP mode
- Discard cached embeddings on dimension mismatch during incremental re-index
- Add MCP embedQuery retry for transient failures
- Add 16 unit tests covering both core and MCP HTTP paths
- Fix README: concise, accurate env var docs
2026-03-20 01:32:49 -04:00
Gergo Magyar
1d27ad09a2 test(type-resolution): assert parameterTypes on graph nodes in integration tests
Add parameterTypes to graph node properties (parse-worker + parsing-processor)
so integration tests can verify extracted parameter types per language:
- Java: ['int'] on lookup(int) overload
- C#: ['int'] on Lookup(int) overload
- C++: ['int'] on lookup(int) overload
- Kotlin: ['Int'] on lookup(Int) overload

Add getNodesByLabelFull helper for property-level assertions.
2026-03-19 22:51:16 +00:00
Gergo Magyar
bc771574d8 test(type-resolution): Phase P integration tests + fixes for all overloading languages
Integration tests for overload disambiguation (Java, Kotlin, C#, C++)
and virtual dispatch (Java, TypeScript) with strict toBe() assertions.

Unit tests verify exact parameterTypes extraction per language:
- Java: ['int'], ['String'], ['int', 'String']
- Kotlin: ['Int'], ['String']
- C#: ['int'], ['string']
- C++: ['int'], ['string']

Fixes discovered during testing:
- extractSimpleTypeName: handle Java integral_type/boolean_type/etc
- tryOverloadDisambiguation: unwrap C# argument + Kotlin value_argument
  wrapper nodes; traverse Kotlin call_suffix for value_arguments
- Kotlin boxed→primitive normalization (Int→int, Long→long, etc.)
- C++ tree-sitter queries: capture pointer-returning inline class methods
- extractFunctionName: handle C++ field_identifier for inline methods
2026-03-19 22:47:24 +00:00
Gergo Magyar
3e29f4e4b9 fix(symbol-table): store all overloads in fileIndex instead of last-write-wins
The fileIndex Map stored SymbolDefinition per name, silently dropping
earlier overloads via Map.set(). Changed to SymbolDefinition[] so all
same-name methods (e.g., Java overloads) survive in same-file resolution.

Added lookupExactAll() for resolution-context to pass all same-file
candidates through to candidate filtering.
2026-03-19 21:37:21 +00:00
Gergo Magyar
06994e474a fix(type-resolution): address PR #387 review — dead code, nullable_type, scope boundaries + integration tests
- Remove dead replayPendingItems array and inert if-block in type-env.ts
- Add nullable_type fallback in extractKotlinDeclaration for val x: User? local vars
- Tighten isCSharpNullableDecl to avoid substring false positives on type names
- Add missing scope boundaries: function_expression (TS), constructor_declaration/
  local_function_statement/lambda_expression (C#) in null-check narrowing walkers
- Extend null-check narrowing fixtures and add 4 integration tests covering:
  Kotlin local variable nullable, C# constructor + lambda, TS function expression
2026-03-19 21:06:05 +00:00
Gergo Magyar
e9ccec1a52 test(type-resolution): add integration tests for Milestone D across all 11 languages + fix Kotlin null-check narrowing
Adds 17 new fixture directories and 23 new describe blocks covering every
feature in Milestone D (Phases A, B, C) with full cross-language integration
test coverage:

Phase A — Fixpoint Completeness:
- TS/JS object destructuring (const { field } = obj → fieldAccess resolution)
- TS/JS post-fixpoint for-loop replay (iterable var resolved by fixpoint)
- Rust struct_pattern destructuring (let Point { x, y } = p)

Phase B — Inheritance & Receivers:
- Grandparent MRO (depth-2 C→B→A) for all 9 OOP languages:
  TS, Kotlin, C#, C++, Java, PHP, Python, Ruby, JS
- Go inc/dec write access (obj.Field++/-- emit ACCESSES write edges)

Phase C — Branch-Sensitive Narrowing:
- Null-check narrowing for TS (!==null, !=null, !==undefined),
  C# (!=null, is not null), and Kotlin (!=null)

Bug fix — Kotlin null-check narrowing (3 issues in jvm.ts):
1. patternBindingNodeTypes registered 'comparison_expression' but
   tree-sitter-kotlin produces 'equality_expression' for !=
2. Handler checked for 'null_literal' named child but 'null' is an
   anonymous node in the Kotlin grammar
3. extractKotlinParameter only searched for 'user_type' direct child,
   missing 'nullable_type' wrapper (so x: User? never got a base binding)

17 fixtures, 23 describe blocks, 705 new lines of test code, 0 failures.
2026-03-19 20:23:06 +00:00
Gergo Magyar
7c72cefd8d feat(type-resolution): implement Milestone D — Phases A, B, C
Phase A — Fixpoint Completeness:
- Extract fixpoint loop into resolveFixpointBindings() with exhaustive switch guard
- Add classDefCache to memoize lookupFuzzy results during fixpoint iteration
- Post-fixpoint for-loop replay: bridge walk-time/fixpoint gap (ex-Phase 9B)
- Object destructuring via fieldAccess items (TS/JS object_pattern, Rust struct_pattern)
- PendingAssignmentExtractor now supports returning arrays for multi-binding patterns

Phase B — Inheritance & Receivers:
- BuildTypeEnvOptions object replaces positional params (future-proof API)
- Heritage pre-pass: thread parent class data from query matches into buildTypeEnv
- walkParentChain() helper: MRO-aware field/method resolution (depth 5, cycle-safe)
- this/self/$this/Me receiver substitution at extractPendingAssignment call site
- Go inc/dec write-access detection via tree-sitter queries

Phase C — Branch-Sensitive Narrowing:
- Rename PATTERN_BRANCH_TYPES → NARROWING_BRANCH_TYPES (semantic expansion)
- Null-check narrowing: != null / !== undefined strips nullable wrapper in truthy branch
- Position-indexed patternOverrides with extractor-provided narrowing ranges
- TS, Kotlin, C# null-check narrowing extractors with if-body range detection

All 3315 existing tests pass. 9 new null-check narrowing tests added.
2026-03-19 17:29:47 +00:00
Gergo Magyar
e6b8edc1ac feat: Phase 9C unified fixpoint with field access and method-call-result binding
Replace the sequential Tier 2b/2a propagation with a unified fixpoint
loop that handles four binding kinds: callResult, copy, fieldAccess,
and methodCallResult. The loop iterates until no new bindings are
produced (max 10 iterations), enabling arbitrary-depth mixed chains:

  const user = getUser();       // callResult → User
  const addr = user.address;    // fieldAccess → Address
  const city = addr.getCity();  // methodCallResult → City
  city.save();                  // resolves to City#save

Infrastructure:
- PendingAssignment union extended with fieldAccess and methodCallResult
- resolveFieldType helper: typeName → class nodeId → lookupFieldByOwner
- resolveMethodReturnType helper: typeName → class nodeId → lookupFuzzyCallable filtered by ownerId
- Fixpoint also resolves reverse-order copy chains that single-pass missed

Languages: TS, JS, Java, Kotlin, C#, Go, Rust, Python, PHP, Ruby, C++.
Each gets field access and/or method-call-with-receiver detection in
extractPendingAssignment, plus method-chain-binding test fixtures.
2026-03-19 11:50:50 +00:00
Gergo Magyar
5769872b70 feat: Phase 9 call-result variable binding across 11 languages
Activate the dormant Tier 2b pendingCallResults infrastructure in
type-env.ts by extending each language's extractPendingAssignment to
emit { kind: 'callResult', lhs, callee } when the RHS of an untyped
variable declaration is a simple function call.

This enables `var user = getUser(); user.save()` to resolve at TypeEnv
build time. Tier 2b now runs before Tier 2a copy-propagation, enabling
mixed chains like `const user = getUser(); const alias = user;
alias.save()`.

Languages: TS, JS, Java, Kotlin, C#, Go, Rust, Python, PHP, Ruby, C++.
Swift excluded. Each language gets a call-result-binding test fixture
and integration tests.

Conservative: only simple calls (no method calls with receivers), only
when exactly one callable matches, first-writer-wins.
2026-03-19 08:59:16 +00:00
Abhigyan Patwari
60c93d7d4a
feat: upgrade @ladybugdb/core to 0.15.2 and remove segfault workarounds (#374)
* feat: upgrade @ladybugdb/core to 0.15.2 and remove segfault workarounds

The upstream fix (ladybug-nodejs#1) resolves the child QueryResult lifetime
segfault, making .close() safe on all platforms. This removes 6 workaround
sites:

- Remove `dangerouslyIgnoreUnhandledErrors` from vitest config
- Remove platform-conditional .close() guards in global-setup and test helper
- Delete test/setup.ts (process._getActiveHandles unref hack)
- Replace no-op cleanup in test-indexed-db.ts with real adapter close
- Fix pool adapter closeOne() to properly close connections with shared
  Database refcount guard and orphaned connection handling in checkin()
- Update segfault-related comments across the codebase

Also bumps @ladybugdb/wasm-core to ^0.15.2 in gitnexus-web for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: keep dangerouslyIgnoreUnhandledErrors for macOS N-API exit crash

The N-API destructor ordering crash during worker fork exit on macOS is
independent of the QueryResult lifetime fix in 0.15.2. Tests pass, but
the exit triggers a crash. Keep the flag with an updated comment
explaining the actual cause. Can be removed once LadybugDB fixes all
destructor ordering issues upstream.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: unify test run for single-pass coverage

- Update `npm test` to run all tests (unit + integration + lbug-db)
  via `vitest run` instead of `vitest run test/unit`
- Add `test:unit` script for running unit tests only
- Remove `ci-integration.yml` — the per-file lbug-db process isolation
  is no longer needed with `dangerouslyIgnoreUnhandledErrors` and
  `fileParallelism: false` handling fork exit issues
- Update `ci-unit-tests.yml` to run all tests with build + coverage
- Simplify `ci.yml` gate (two jobs: quality + tests)
- Simplify `ci-report.yml` (single coverage artifact, no merge step)

* fix: update cli-commands test for renamed test:all → test:unit script

* fix: set USERPROFILE in setup-skills test for Windows compatibility

os.homedir() checks USERPROFILE on Windows, not HOME.

* fix: add isolate: false to lbug-db project to prevent fork crashes

On macOS, N-API destructors crash fork workers on exit. With
isolate: true (default), vitest recycles the fork between files,
triggering the crash after each file. After several crashes, the
remaining lbug-db files never execute.

isolate: false keeps all 8 lbug-db files in a single fork — the
fork only exits once after all files complete, and that single exit
crash is caught by dangerouslyIgnoreUnhandledErrors.

* fix: add unique sequence.groupOrder to vitest projects

Vitest v4 requires unique groupOrder when projects have different
maxWorkers (lbug-db has fileParallelism: false → maxWorkers: 1).

* fix: await async close() in global-setup and remove isolate: false

global-setup.ts called conn.close() and db.close() without await —
these return Promise<void> in @ladybugdb/core 0.15.2.  The setup
function returned before the DB was fully closed, so vitest forks
hit a stale file lock when opening the same DB path, crashing the
lbug-db worker before any test ran.

isolate: false caused native state corruption after 2-3 open/close
cycles in the same fork (vitest-specific, not reproducible in plain
Node.js).  Without it, each file gets its own module scope and the
N-API destructor crash at fork exit is caught by
dangerouslyIgnoreUnhandledErrors.

Also fixes fire-and-forget close() calls in the pool adapter —
try/catch around an async close() never catches rejections; changed
to .catch(() => {}) for proper unhandled-rejection prevention.

Before: 0/8 lbug-db files ran on macOS CI (fork crash).
After:  8/8 pass, 84 files, 3077 tests, zero errors.

* fix: update project index references in AGENTS.md and CLAUDE.md to reflect correct symbol counts and relationships

* feat: enhance lbug adapter with external database support and write operation validation

* feat: create ci-tests workflow for comprehensive test coverage across platforms

* ci: move PR report inline to ci.yml, delete ci-report.yml

The old ci-report.yml used workflow_run which always runs code from
the default branch (main). This meant the PR comment used main's
stale report template that still referenced the old unit/integration
split architecture — causing "Merge coverage reports" failures.

Moving the report inline to ci.yml means it runs from the PR branch
and uses the current report template. The report now shows:
- per-platform status (Ubuntu/Windows/macOS columns)
- unified test counts from the single vitest run
- coverage with base branch (main) delta comparison
- commit SHA for traceability

Also removes the save-pr-meta job since the report no longer needs
a separate workflow_run trigger.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Gergo Magyar <gergomagyar@icloud.com>
2026-03-19 08:25:43 +00:00
Gergo Magyar
1e19986ef3 fix(tests): update property edge and write access expectations across multiple language tests 2026-03-18 22:25:30 +00:00
Gergő Magyar
973c7bfbf0
feat: ACCESSES edge type with read/write field access tracking (#372)
* feat: Phase 1 ACCESSES edge type — read tracking from chain resolution

Add ACCESSES relationship type to track field read access during call
chain resolution. When walkMixedChain resolves a field access (e.g.,
user.address.save()), an ACCESSES edge with reason 'read' is emitted
from the calling function to the Property node.

Schema: ACCESSES added to RelationshipType, REL_TYPES, VALID_RELATION_TYPES,
context queries, tools/resources descriptions. Excluded from default
impact BFS to prevent traversal explosion.

Implementation: resolveFieldAccessType now returns FieldResolution with
fieldNodeId. walkMixedChain accepts optional onFieldResolved callback.
makeAccessEmitter factory provides Set-based dedup per source node.

Bug fix: Added Java 'field_access' to FIELD_ACCESS_NODE_TYPES — was
missing, causing extractMixedChain to fail for Java member access.

* feat: Phase 2 ACCESSES write edges — assignment detection across 12 languages

Add tree-sitter query patterns for field write detection (obj.field = value)
across all supported languages: TS/JS, Python, Java, Go, C++, C#, Rust,
PHP, Ruby (setter syntax), Kotlin, Swift.

Processing: Sequential path handles assignment captures inline. Worker
path extracts ExtractedAssignment data for deferred resolution via new
processAssignmentsFromExtracted function.

Bug fix: Kotlin/Swift assignment queries used invalid navigation_expression
wrapper — fixed to match actual directly_assignable_expression AST structure.

Tests: Write access integration tests for TS, Java, Python, Go with
dedicated fixtures. All use strict toBe() assertions.

* test: add unit tests for call-routing, shared type extractors, and symbol-table branches

Add 215 new unit tests across 3 files to increase branch coverage toward
the 23% global threshold (was 21.49%):

- call-routing.test.ts (49 tests): Ruby call routing — require/require_relative,
  include/extend/prepend heritage, attr_accessor properties with YARD types
- shared-type-extractors.test.ts (108 tests): pure string functions —
  extractElementTypeFromString, stripNullable, extractReturnTypeName,
  methodToTypeArgPosition, getContainerDescriptor
- symbol-table.test.ts (+29 tests): Property/fieldByOwner index, metadata
  spread branches, lazy callable index, lookupExactFull shape

* fix: defer write-access resolution to fix Ruby cross-file property timing

Ruby attr_accessor properties are registered during processCalls (not
the parsing phase), so lookupFieldByOwner fails when service.rb is
processed before models.rb. Fix by collecting pending write-access
edges during the file loop and resolving them after all files are done.

Also adds write-access integration tests and fixtures for 7 languages
(C++, C#, JS, Kotlin, PHP, Ruby, Rust), Ruby compound assignment query,
PHP static property write query, and Kotlin property type extraction.

* fix: address PR #372 review — write-access constructor bindings parity and docs

- Add verified constructor bindings fallback to write-access resolution
  in both sequential path (receiverIndex lookup) and worker path
  (constructorBindings param for processAssignmentsFromExtracted),
  closing the read/write ACCESSES edge asymmetry for factory-returned
  receivers
- Clarify inner guard control flow comment in processCalls match loop
- Document Go inc_statement/dec_statement gap in roadmap
- Clarify PHP nullsafe write footnote (invalid syntax, not just untracked)
- Update symbol-table tests for intentional fieldByOwner behavior change
  (Properties without declaredType now indexed for dynamic language
  write-access tracking)
2026-03-19 03:48:04 +05:30
Gergő Magyar
11a3d0515c
feat: Phase 8 field/property type resolution (#354)
* feat: Phase 8 field/property type resolution — resolve chained member access

Add field/property type extraction to the type resolution system so that
chained member access like `user.address.save()` resolves the intermediate
receiver type (`address → Address`) through Property symbols in SymbolTable.

Key changes:
- SymbolTable: add `declaredType` field, `fieldByOwner` O(1) index,
  `lookupFieldByOwner()` method, P0 conditional callableIndex invalidation,
  P2 exclude Properties from globalIndex to prevent namespace pollution
- tree-sitter queries: add `definition.property` for TypeScript, Java, Go
- parse-worker: extract declared types for Property nodes via
  `extractPropertyDeclaredType()`, capture field-access receiver info
- call-processor: add `resolveFieldAccessType()` helper and field-access
  branch in both sequential and worker receiver resolution paths
- Integration tests: new field-types test suite verifying end-to-end
  `user.address.save() → Address#save` resolution

* fix: Go tree-sitter query captures field_declaration not field_declaration_list

Post-review fix: the Go struct field query incorrectly put @definition.property
on field_declaration_list (the list container) instead of field_declaration
(the individual field). Also removed unused `language` parameter from
extractPropertyDeclaredType.

* feat: expand field-type tests to 6 languages, fix Go ownerId and Kotlin navigation_expression

- Add integration test fixtures for Java, C#, Go, Kotlin, PHP (alongside existing TS)
- Fix Go: add type_declaration handling in findEnclosingClassId for struct fields
  (field_declaration → field_declaration_list → struct_type → type_spec → type_declaration)
- Fix Kotlin: add navigation_expression handling in field-access resolution
  (Kotlin uses navigation_expression + navigation_suffix, not member_expression)
- Add extractMemberAccessParts helper in call-processor for cross-language member access
- All 24 field-type tests pass across 6 languages, 181 Go+Kotlin tests pass with no regressions

* refactor: split HAS_METHOD into HAS_METHOD + HAS_PROPERTY edge types

Property nodes now use HAS_PROPERTY edges instead of HAS_METHOD, giving
the graph schema proper semantic separation between methods and fields.

- HAS_METHOD: Method, Constructor, Function (when inside a class)
- HAS_PROPERTY: Property nodes (class fields, struct fields, attributes)

MRO processor only reads HAS_METHOD — properties correctly excluded from
method resolution order. Impact analysis accepts both edge types.

Updated 12 files: graph types, schema, tools docs, parse-worker,
parsing-processor, call-processor, and 6 test files.

* fix(test): update security test to expect 7 VALID_RELATION_TYPES (added HAS_PROPERTY)

* test: add unit tests for Phase 8 SymbolTable features (39 tests, up from 19)

Cover all new branches: declaredType metadata, Property exclusion from
globalIndex, conditional callableIndex invalidation, lookupFieldByOwner
(happy path + edge cases), lookupFuzzyCallable filtering, and clear()
with fieldByOwner. Fixes branch coverage threshold (21.8% → 23%+).

* feat: Phase 8B mixed field+method chain resolution, C++/Rust chain fixes

Unify field and method chain resolution into a single `extractMixedChain`
walker that handles interleaved patterns like `svc.getUser().address.save()`.
Fix C++ chain calls (tree-sitter-cpp `field_expression` uses `argument` not
`object`), Rust unit struct instantiation (`let svc = TypeName;`), and add
stdlib passthrough for `unwrap()`/`clone()`/`expect()` in chain loops.

Key changes:
- Replace `receiverCallChain` + `receiverFieldAccess` with unified
  `receiverMixedChain: MixedChainStep[]` on ExtractedCall
- Add `extractMixedChain` in utils.ts (handles both call_expression and
  field_expression nodes, including C++ `argument` field)
- Add `TYPE_PRESERVING_METHODS` set for stdlib identity operations
- Add C++ inline method double-indexing guard in parsing-processor.ts
  and parse-worker.ts
- Add Rust unit struct recognition in type-extractors/rust.ts
- Split field-types.test.ts into per-language test files
- Add ts-mixed-chain fixture and integration tests
- Resolve rust.test.ts todo: Option<T>.unwrap().save() now works
- Update roadmap: Phases 7+8 complete, Phase 9 is next

* fix: Python declaredType extraction and sequential-path property registration

- Move @definition.property capture from expression_statement to assignment
  node in Python queries so Strategy 1 childForFieldName('type') succeeds
- Pass item.declaredType through ctx.symbols.add in sequential call-processor
  path, matching worker path behavior (fixes Ruby YARD declaredType drop)
- Add Python chain resolution integration test (user.address.save → Address#save)
- Update Rust/Python status in roadmap and system docs to reflect actual coverage

* fix: Python/Ruby field type disambiguation and Rust chain test

Three fixes from PR #354 third review:

1. Python typed_parameter name extraction: tree-sitter-python's
   typed_parameter uses positional children for the name, not a named
   field. TypeEnv and extractParameter now fall back to firstNamedChild.

2. Ruby/Python call-step field resolution: Ruby's AST uses `call` nodes
   for both property access and method calls. The chain walker now tries
   resolveFieldAccessType before resolveCallTarget for call steps, so
   attr_accessor properties resolve via declaredType.

3. Rust chain resolution test: added missing integration test asserting
   user.address.save() resolves to Address#save.

Also splits C/C++ and TS/JS columns in type-resolution-system.md
language matrix with footnotes for accuracy.

1062 resolver integration tests passing, 0 failures.

* refactor: Phase 8 code review cleanup — extract walkMixedChain, fix MCP agent gaps

- Extract duplicated chain resolution loop into shared walkMixedChain() helper,
  eliminating ~60 lines of copy-pasted code between sequential and worker paths
- Add returnType to ResolveResult, removing redundant lookupFuzzy+find per chain step
- Fix context() tool to include HAS_METHOD, HAS_PROPERTY, OVERRIDES in queries
  so agents can discover class members
- Fix p.declaredType Cypher example (column doesn't exist) → p.description
- Add HAS_METHOD, HAS_PROPERTY, OVERRIDES to schema resource
- Document HAS_METHOD/HAS_PROPERTY in impact tool description
- Delete dead code extractMemberAccessParts (superseded by extractMixedChain)
- Replace any with SyntaxNode on extractPropertyDeclaredType
- Add Rust deep-field-chain test (5 tests), Java mixed-chain (4), Go mixed-chain (4)
- All 1075 tests pass (13 new, 0 regressions)

* refactor: type SymbolDefinition.type as NodeLabel, add O(1) receiver index

- Change SymbolDefinition.type from string to NodeLabel union (35 members)
  across symbol-table.ts, parse-worker.ts, parsing-processor.ts — compiler
  now enforces correctness at all comparison/assignment sites
- Replace O(N*M) linear scan in lookupReceiverType with pre-built
  ReceiverTypeIndex (Map<funcName, Map<varName, Entry>>) for O(1) lookups
  with proper ambiguity handling and file-level fallback
- All 1075 tests pass, 0 regressions

* fix: capture C++ pointer/ref fields, Kotlin data class props, PHP constructor promotion

Add tree-sitter query patterns for three previously missed property declaration
forms: C++ pointer/reference member fields (Address* addr; Address& ref;),
Kotlin primary constructor val/var parameters (data class User(val name: String)),
and PHP 8.0+ constructor property promotion (public Address $address).

Fix "10 languages" off-by-one in docs (Ruby is single-level only, not deep chain).
Update Python feature matrix cell from No* to Yes* after 31b95f0 fix.

11 new integration tests with per-language fixtures verify property capture,
HAS_PROPERTY edge emission, and field-access chain resolution.
2026-03-18 18:47:33 +00:00
Chirag Nighut
aa1bab597b
feat: add Python enumerate() for-loop support with nested tuple patterns (#356)
- Handle `for i, k, v in enumerate(d.items())` — flat pattern
- Handle `for i, (k, v) in enumerate(d.items())` — nested tuple_pattern
- Handle `for (k, v) in enumerate(users)` — parenthesized tuple as top-level

Extract helper functions for cleaner code:
- `extractMethodCall()` — deduplicate method call parsing
- `collectPatternIdentifiers()` — recursively collect identifiers from patterns

Add unit tests for TypeEnv and integration tests verifying CALLS edges.

Made-with: Cursor

Co-authored-by: chirag-nighut <chiragnighut@gmail.com>
2026-03-18 13:05:10 +00:00
Hazem
60ede20a11
fix: MCP server crashes under parallel tool calls (#326) (#349)
* fix: MCP server crashes under parallel tool calls (#326)

* fix: ensure full connection pool is pre-created to avoid race conditions during query execution

* fix: improve graceful shutdown handling with exit codes

* fix: resolve critical concurrency bugs in connection pool init

- Add initPromises dedup map to prevent double-init race when parallel
  tool calls trigger initLbug for the same repoId simultaneously
- Move pool.set() after FTS load so concurrent checkout can't grab a
  connection mid-async-init (FTS race on available[0])
- Replace lazy createConnection growth path with integrity error — pool
  is pre-warmed, lazy creation would silence stdout during active queries
- Add preWarmActive flag so watchdog timer skips stdout restore during
  the synchronous pre-warm loop
- Unify stdout capture: server.ts imports realStdoutWrite from
  lbug-adapter instead of capturing its own copy

* test: add connection pool parallel stability tests

7 integration tests covering concurrent query safety, waiter queue
overflow, stdout.write restoration, connection leak detection, initLbug
deduplication, atomic pool visibility, and mixed query types.

* fix: run LadybugDB tests sequentially via vitest projects config

Vitest's projects feature splits test files into two groups: lbug-db
(fileParallelism: false) and default (parallel). This prevents native
mmap file-lock conflicts on Windows without requiring the CI shell loop
locally.

* test: add enrichment Promise.all regression test for #292/#316

Verifies that 3 concurrent queries via Promise.all (the exact pattern
from the impact command's enrichment phase at local-backend.ts:1415)
complete without SIGSEGV on a pre-warmed connection pool.
2026-03-18 13:02:01 +00:00
Gergő Magyar
604b575e4b
feat: Phase 7 type resolution — return-aware loop inference & PHP class-property iterables (#341)
* feat(type-resolution): Phase 7.1+7.2 foundation — ReturnTypeLookup, context object, pendingCallResults

- Move extractReturnTypeName + helpers from call-processor.ts to type-extractors/shared.ts
  (breaks circular import risk: call-processor → type-env → type-extractors → call-processor)
- Add SymbolTable.lookupFuzzyCallable(name) — lazy callable-only index, O(1) per call,
  invalidated on add(); avoids per-call .filter() on lookupFuzzy results
- Add ReturnTypeLookup interface (conservative: undefined when 0 or 2+ callables match)
- Add ForLoopExtractorContext interface — replaces 4 positional params with context object;
  update all 10 language extractor implementations (go, ts, py, jvm×2, cs, rs, rb, php, c-cpp)
- Add PendingAssignment discriminated union (kind: 'copy' | 'callResult');
  update PendingAssignmentExtractor in all 9 language extractors that implement it
- Wire buildTypeEnv: build ReturnTypeLookup from optional symbolTable; split pendingAssignments
  into pendingCopies + pendingCallResults; add Tier 2b call-result propagation loop
- Update call-processor.test.ts to import extractReturnTypeName from shared.ts

* feat(type-resolution): Phase 7.3 — call_expression iterables in for-loop extractors (7 languages)

Extends for-loop type extraction in all 7 typed-iteration languages to
resolve element types when the iterable is a direct function call.

**New capability**: `for (var u : getUsers())` in Java, `for u in get_users()`
in Python, `for user in getUsers()` in TypeScript, etc. now resolve
`u`/`user` to the callee's return element type via lookupRawReturnType +
extractElementTypeFromString.

Changes per language:
- types.ts: extend ReturnTypeLookup with lookupRawReturnType (raw return
  string for container-type extraction); update ForLoopExtractorContext
  with returnTypeLookup field
- type-env.ts: implement lookupRawReturnType on the concrete ReturnTypeLookup
  built in buildTypeEnv (same guards as lookupReturnType, no extractReturnTypeName)
- go.ts: call_expression branch in range_clause — identifier func or
  selector_expression method; existing isChannelType guards updated
- typescript.ts: identifier fn branch inside call_expression handler
- python.ts: identifier fn branch inside call handler
- jvm.ts (Java): method_invocation without object field in enhanced_for_statement
- jvm.ts (Kotlin): simple_identifier callee branch in call_expression node
- csharp.ts: identifier fn branch in invocation_expression handler
- rust.ts: identifier func branch in call_expression handler (alongside
  existing field_expression/method-call path)

All branches follow the same conservative pattern:
  lookupRawReturnType(callee) → extractElementTypeFromString → bind loop var

* feat(type-resolution): Phase 7.4 — PHP \$this->property iterable via @var class property scan

Adds Strategy C to PHP's extractForLoopBinding for the pattern:

  foreach (\$this->property as \$item)

when Strategy A (resolveIterableElementType) and Strategy B (scopeEnv lookup)
both fail to find the element type.

Strategy C: when the iterable is a member_access_expression with object '$this',
walk up the AST to the enclosing class_declaration, scan its declaration_list
for a property_declaration whose variable_name matches the property, and extract
the element type from:
  1. PHPDoc @var annotation on a preceding comment sibling (/** @var User[] */)
  2. PHP 7.4+ native type field (e.g. UserRepo \$repo — skips generic 'array')

This eliminates the @param workaround that was previously required in the
php-foreach-member-access fixture (which used @param User[] \$users on the method
to populate the method's scopeEnv with a \$users binding).

New helpers in php.ts:
- PHPDOC_VAR_RE: regex for @var extraction
- extractClassPropertyElementType: reads @var or native type from a property_declaration
- findClassPropertyElementType: scans class body for a named property

Tests added (type-env.test.ts):
- PHP: resolves from @var User[] without @param workaround
- PHP: conservative — no binding for unknown property
- PHP: multi-class file — both classes resolve independently

Fixture updated (php-foreach-member-access/App.php):
- Removed the @param User[] \$users workaround from processMembers()
- Test now validates the natural class-property-based resolution path

* docs: mark Phase 7 complete in type-resolution-roadmap.md

Records that 7A (call_expression iterables, 7 languages), 7B (PHP
$this->property via @var scan), and 7C (ReturnTypeLookup + context object)
are all shipped. Adds implementation notes and strikethroughs on resolved
language-specific gaps.

* fix(docs): update project references to feat-phase7-type-resolution in AGENTS.md and CLAUDE.md

* feat(type-resolution): Phase 7.5 — PHP call_expression foreach + integration tests for 7 languages

Add integration test coverage for Phase 7.3's call_expression iterable
resolution across all 7 languages (Go, TypeScript, Python, Java, Kotlin,
PHP, Rust). Each test creates a fixture with competing User/Repo classes
that both define save(), then verifies for-loop iteration over a function
call's return value resolves to the correct class.

PHP was missing function_call_expression support in its for-loop extractor.
Three changes fix this:
- php.ts extractForLoopBinding: handle function_call_expression and
  member_call_expression iterables via returnTypeLookup
- php.ts normalizePhpReturnType: preserve array notation (User[]) in
  SymbolTable so lookupRawReturnType returns useful container types
- parse-worker.ts + parsing-processor.ts: upgrade uninformative AST
  return types (array, iterable) with PHPDoc @return annotations

35 new integration tests (5 per language), 2525 total tests passing.

* fix(type-resolution): address PR #341 review findings — PHP asymmetry + dormant infrastructure docs

- Replace normalizePhpType with extractElementTypeFromString in PHP call-expression
  foreach paths, aligning with all 6 other language extractors and preventing
  incorrect binding of bare non-container types like User
- Add NOTE comments clarifying pendingCallResults Tier 2b is infrastructure-ready
  but no extractor populates it yet
- Expand Go channel-type comments explaining why non-channel assumption is safe

* fix(type-resolution): address verification review — docs accuracy + PHP fallback guard

- Roadmap lines 86/100: correct pendingCallResults from "active" to "dormant infrastructure (Phase 9)"
- type-resolution-system.md line 363: update to reflect Phase 7.3 loop inference is delivered
- type-resolution-system.md line 409: clarify for-loop call-expression resolution (done) vs general assignment propagation (pending)
- php.ts:127: add declaration_list type guard on fallback to prevent silent wrong results
2026-03-18 08:39:38 +00:00
Gergo Magyar
02dfab578c fix(test): add --repo to CLI e2e tool tests for multi-repo environment 2026-03-18 08:12:25 +00:00