feat: Add Rust trait inheritance and impl block extraction with method receiver type support
Addresses Rust's impl block syntax where trait implementations (`impl Trait for Type`) and trait supertraits (`trait Sub: Super`) create inheritance relationships. Adds getReceiverType to extract method receiver types from impl blocks, enabling proper method-to-struct relationships and qualified name resolution. Verified against Deno codebase and moved from "Needs Verification" to completed language support.
This commit is contained in:
@@ -650,6 +650,78 @@ pub trait Repository {
|
||||
expect(traitNode).toBeDefined();
|
||||
expect(traitNode?.name).toBe('Repository');
|
||||
});
|
||||
|
||||
it('should extract impl Trait for Type as implements edges', () => {
|
||||
const code = `
|
||||
pub struct MyCache {}
|
||||
|
||||
pub trait Cache {
|
||||
fn get(&self, key: &str) -> Option<String>;
|
||||
}
|
||||
|
||||
impl Cache for MyCache {
|
||||
fn get(&self, key: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
`;
|
||||
const result = extractFromSource('cache.rs', code);
|
||||
|
||||
// Should have an unresolved reference for implements
|
||||
const implRef = result.unresolvedReferences.find(
|
||||
(r) => r.referenceKind === 'implements' && r.referenceName === 'Cache'
|
||||
);
|
||||
expect(implRef).toBeDefined();
|
||||
|
||||
// The struct MyCache should be the source
|
||||
const myCacheNode = result.nodes.find((n) => n.name === 'MyCache' && n.kind === 'struct');
|
||||
expect(myCacheNode).toBeDefined();
|
||||
expect(implRef?.fromNodeId).toBe(myCacheNode?.id);
|
||||
});
|
||||
|
||||
it('should extract trait supertraits as extends references', () => {
|
||||
const code = `
|
||||
pub trait Display {}
|
||||
|
||||
pub trait Error: Display {
|
||||
fn description(&self) -> &str;
|
||||
}
|
||||
`;
|
||||
const result = extractFromSource('error.rs', code);
|
||||
|
||||
const extendsRef = result.unresolvedReferences.find(
|
||||
(r) => r.referenceKind === 'extends' && r.referenceName === 'Display'
|
||||
);
|
||||
expect(extendsRef).toBeDefined();
|
||||
|
||||
const errorTrait = result.nodes.find((n) => n.name === 'Error' && n.kind === 'trait');
|
||||
expect(errorTrait).toBeDefined();
|
||||
expect(extendsRef?.fromNodeId).toBe(errorTrait?.id);
|
||||
});
|
||||
|
||||
it('should not create implements edges for plain impl blocks', () => {
|
||||
const code = `
|
||||
pub struct Counter {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
pub fn new() -> Counter {
|
||||
Counter { count: 0 }
|
||||
}
|
||||
pub fn increment(&mut self) {
|
||||
self.count += 1;
|
||||
}
|
||||
}
|
||||
`;
|
||||
const result = extractFromSource('counter.rs', code);
|
||||
|
||||
// Should have no implements references (no trait involved)
|
||||
const implRefs = result.unresolvedReferences.filter(
|
||||
(r) => r.referenceKind === 'implements'
|
||||
);
|
||||
expect(implRefs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Java Extraction', () => {
|
||||
|
||||
Reference in New Issue
Block a user