feat: Add Swift inheritance extraction for class, struct, enum, and protocol relationships
Addresses Swift's inheritance_specifier syntax where type relationships are specified after colons (e.g. `class UploadRequest: DataRequest, Sendable`). Extracts user_type > type_identifier children from inheritance_specifier nodes as 'extends' references to properly model Swift's inheritance, protocol conformance, and struct conformance patterns in the code graph.
This commit is contained in:
@@ -818,6 +818,47 @@ public protocol Repository {
|
|||||||
expect(protocolNode).toBeDefined();
|
expect(protocolNode).toBeDefined();
|
||||||
expect(protocolNode?.name).toBe('Repository');
|
expect(protocolNode?.name).toBe('Repository');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should extract class inheritance and protocol conformance', () => {
|
||||||
|
const code = `
|
||||||
|
class DataRequest: Request {
|
||||||
|
func validate() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadRequest: DataRequest, Sendable {
|
||||||
|
func upload() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AFError: Error {
|
||||||
|
case invalidURL
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HTTPMethod: RawRepresentable {
|
||||||
|
let rawValue: String
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol UploadConvertible: URLRequestConvertible {
|
||||||
|
func asURLRequest() throws -> URLRequest
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
const result = extractFromSource('Inheritance.swift', code);
|
||||||
|
|
||||||
|
const extendsRefs = result.unresolvedReferences.filter(
|
||||||
|
(r) => r.referenceKind === 'extends'
|
||||||
|
);
|
||||||
|
|
||||||
|
// DataRequest extends Request
|
||||||
|
expect(extendsRefs.find((r) => r.referenceName === 'Request')).toBeDefined();
|
||||||
|
// UploadRequest extends DataRequest and Sendable
|
||||||
|
expect(extendsRefs.find((r) => r.referenceName === 'DataRequest')).toBeDefined();
|
||||||
|
expect(extendsRefs.find((r) => r.referenceName === 'Sendable')).toBeDefined();
|
||||||
|
// AFError extends Error
|
||||||
|
expect(extendsRefs.find((r) => r.referenceName === 'Error')).toBeDefined();
|
||||||
|
// HTTPMethod extends RawRepresentable
|
||||||
|
expect(extendsRefs.find((r) => r.referenceName === 'RawRepresentable')).toBeDefined();
|
||||||
|
// UploadConvertible extends URLRequestConvertible
|
||||||
|
expect(extendsRefs.find((r) => r.referenceName === 'URLRequestConvertible')).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Kotlin Extraction', () => {
|
describe('Kotlin Extraction', () => {
|
||||||
|
|||||||
@@ -583,6 +583,9 @@ export class TreeSitterExtractor {
|
|||||||
});
|
});
|
||||||
if (!structNode) return;
|
if (!structNode) return;
|
||||||
|
|
||||||
|
// Extract inheritance (e.g. Swift: struct HTTPMethod: RawRepresentable)
|
||||||
|
this.extractInheritance(node, structNode.id);
|
||||||
|
|
||||||
// Push to stack for field extraction
|
// Push to stack for field extraction
|
||||||
this.nodeStack.push(structNode.id);
|
this.nodeStack.push(structNode.id);
|
||||||
const body = getChildByField(node, this.extractor.bodyField) || node;
|
const body = getChildByField(node, this.extractor.bodyField) || node;
|
||||||
@@ -1309,6 +1312,23 @@ export class TreeSitterExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swift: inheritance_specifier > user_type > type_identifier
|
||||||
|
// Used for class inheritance, protocol conformance, and protocol inheritance
|
||||||
|
if (child.type === 'inheritance_specifier') {
|
||||||
|
const userType = child.namedChildren.find((c: SyntaxNode) => c.type === 'user_type');
|
||||||
|
const typeId = userType?.namedChildren.find((c: SyntaxNode) => c.type === 'type_identifier');
|
||||||
|
if (typeId) {
|
||||||
|
const name = getNodeText(typeId, this.source);
|
||||||
|
this.unresolvedReferences.push({
|
||||||
|
fromNodeId: classId,
|
||||||
|
referenceName: name,
|
||||||
|
referenceKind: 'extends',
|
||||||
|
line: typeId.startPosition.row + 1,
|
||||||
|
column: typeId.startPosition.column,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Recurse into container nodes (e.g. field_declaration_list in Go structs)
|
// Recurse into container nodes (e.g. field_declaration_list in Go structs)
|
||||||
if (child.type === 'field_declaration_list') {
|
if (child.type === 'field_declaration_list') {
|
||||||
this.extractInheritance(child, classId);
|
this.extractInheritance(child, classId);
|
||||||
|
|||||||
Reference in New Issue
Block a user