From 31b95f08d0f4e2b3688389f2de9cf36435dc5739 Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Wed, 18 Mar 2026 14:58:00 +0000 Subject: [PATCH] fix: Python declaredType extraction and sequential-path property registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- gitnexus/src/core/ingestion/call-processor.ts | 6 ++++-- gitnexus/src/core/ingestion/tree-sitter-queries.ts | 2 +- gitnexus/test/integration/resolvers/python.test.ts | 9 +++++++++ type-resolution-roadmap.md | 4 ++-- type-resolution-system.md | 2 +- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/gitnexus/src/core/ingestion/call-processor.ts b/gitnexus/src/core/ingestion/call-processor.ts index 4db61b4ad..9c9da454a 100644 --- a/gitnexus/src/core/ingestion/call-processor.ts +++ b/gitnexus/src/core/ingestion/call-processor.ts @@ -234,8 +234,10 @@ export const processCalls = async ( description: item.accessorType, }, }); - ctx.symbols.add(file.path, item.propName, nodeId, 'Property', - propEnclosingClassId ? { ownerId: propEnclosingClassId } : undefined); + ctx.symbols.add(file.path, item.propName, nodeId, 'Property', { + ...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}), + ...(item.declaredType ? { declaredType: item.declaredType } : {}), + }); const relId = generateId('DEFINES', `${fileId}->${nodeId}`); graph.addRelationship({ id: relId, sourceId: fileId, targetId: nodeId, diff --git a/gitnexus/src/core/ingestion/tree-sitter-queries.ts b/gitnexus/src/core/ingestion/tree-sitter-queries.ts index 0b09f01e8..702f78cce 100644 --- a/gitnexus/src/core/ingestion/tree-sitter-queries.ts +++ b/gitnexus/src/core/ingestion/tree-sitter-queries.ts @@ -183,7 +183,7 @@ export const PYTHON_QUERIES = ` (expression_statement (assignment left: (identifier) @name - type: (type))) @definition.property + type: (type)) @definition.property) ; Heritage queries - Python class inheritance (class_definition diff --git a/gitnexus/test/integration/resolvers/python.test.ts b/gitnexus/test/integration/resolvers/python.test.ts index cd8d1a24b..9fd8ae86c 100644 --- a/gitnexus/test/integration/resolvers/python.test.ts +++ b/gitnexus/test/integration/resolvers/python.test.ts @@ -1314,4 +1314,13 @@ describe('Field type resolution (Python)', () => { expect(edgeSet(propEdges)).toContain('User → name'); expect(edgeSet(propEdges)).toContain('Address → city'); }); + + it('resolves user.address.save() → Address#save via field type', () => { + const calls = getRelationships(result, 'CALLS'); + const saveCalls = calls.filter(e => e.target === 'save'); + const addressSave = saveCalls.find( + e => e.source === 'process_user' && e.targetFilePath.includes('models'), + ); + expect(addressSave).toBeDefined(); + }); }); diff --git a/type-resolution-roadmap.md b/type-resolution-roadmap.md index 50485c1ab..50fef9eed 100644 --- a/type-resolution-roadmap.md +++ b/type-resolution-roadmap.md @@ -146,8 +146,8 @@ Model class / struct fields so chained member access can be resolved more accura | Go | ✅ `field_declaration` | ✅ Strategy 1 (type field) | ✅ | | | Kotlin | ✅ `property_declaration` | ✅ Strategy 4 (variable_declaration) | ✅ | New strategy added | | PHP | ✅ `property_declaration` | ✅ Strategy 1 + PHPDoc @var fallback | ✅ | Strategy 5 for pre-7.4 | -| Rust | ✅ `field_declaration` | ✅ Strategy 1 (type field) | — | Capture only (no field-access call resolution) | -| Python | ✅ `assignment` with `type` | ⚠️ Class-level only | — | `self.x` pattern needs work | +| Rust | ✅ `field_declaration` | ✅ Strategy 1 (type field) | ✅ | `extractMemberAccessParts` handles `field_expression` via `value`/`field` | +| Python | ✅ `assignment` with `type` | ✅ Class-level annotations | ✅ | `self.x` instance pattern not yet supported | | Ruby | ✅ `attr_*` via call routing | ✅ YARD `@return [Type]` | — | YARD fallback for dynamically typed properties | | C++ | ✅ `field_declaration` via `field_identifier` | ✅ Strategy 1 (type field) | ✅ | | | Swift | ✅ `property_declaration` | ⚠️ Untested | — | | diff --git a/type-resolution-system.md b/type-resolution-system.md index bd20bd38e..c18ccfd24 100644 --- a/type-resolution-system.md +++ b/type-resolution-system.md @@ -378,7 +378,7 @@ So return-type-aware receiver inference already exists in a constrained downstre | Comment-based types | JSDoc | No | No | No | No | No | No | PHPDoc | YARD | No | No | | Return type extraction | JSDoc | No | No | No | No | No | No | PHPDoc | YARD | No | No | -\* Python has a type annotation query for fields but no `declaredType` extraction for the `self.x` pattern yet. +\* Python class-level annotated attributes (`address: Address`) now resolve `declaredType` correctly. The `self.x` instance attribute pattern is not yet supported. ---