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
This commit is contained in:
Gergo Magyar 2026-03-18 14:58:00 +00:00
parent 52c3297143
commit 31b95f08d0
5 changed files with 17 additions and 6 deletions

View file

@ -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,

View file

@ -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

View file

@ -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();
});
});

View file

@ -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 | — | |

View file

@ -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.
---