diff --git a/src/metricsAnalyzer/languages/rustAnalyzer.ts b/src/metricsAnalyzer/languages/rustAnalyzer.ts index 9a867c7..9f208a0 100644 --- a/src/metricsAnalyzer/languages/rustAnalyzer.ts +++ b/src/metricsAnalyzer/languages/rustAnalyzer.ts @@ -180,12 +180,27 @@ export class RustMetricsAnalyzer { if (parent && parent.type === "declaration_list") { const implNode = parent.parent; if (implNode && implNode.type === "impl_item") { - const typeNode = implNode.children.find( - (child) => - child.type === "type_identifier" || - child.type === "generic_type" || - child.type === "scoped_type_identifier" + // For `impl Trait for Type`, prefer the implementing type (after `for`). + // For inherent `impl Type`, use the only type present. + const forIndex = implNode.children.findIndex( + (child) => child.type === "for" ); + const typeNode = + forIndex !== -1 + ? implNode.children + .slice(forIndex + 1) + .find( + (child) => + child.type === "type_identifier" || + child.type === "generic_type" || + child.type === "scoped_type_identifier" + ) + : implNode.children.find( + (child) => + child.type === "type_identifier" || + child.type === "generic_type" || + child.type === "scoped_type_identifier" + ); if (typeNode) { const typeName = this.sourceText.substring( typeNode.startIndex, diff --git a/src/test/metricsAnalyzer/languages/rustAnalyzer.test.ts b/src/test/metricsAnalyzer/languages/rustAnalyzer.test.ts index bcc00f1..95ca04a 100644 --- a/src/test/metricsAnalyzer/languages/rustAnalyzer.test.ts +++ b/src/test/metricsAnalyzer/languages/rustAnalyzer.test.ts @@ -219,6 +219,25 @@ impl Counter { assert.strictEqual(results[0].complexity, 0); }); + test("should use implementing type name for trait impl (impl Trait for Type)", () => { + const sourceCode = ` +use std::fmt; + +struct Point { x: f64, y: f64 } + +impl fmt::Display for Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {})", self.x, self.y) + } +} +`; + const results = analyzer.analyzeFunctions(sourceCode); + + assert.strictEqual(results.length, 1); + // Should use implementing type "Point", not trait "Display" + assert.strictEqual(results[0].name, "Point::fmt"); + }); + test("should analyze impl method with complexity", () => { const sourceCode = ` struct Validator { max: i32 } diff --git a/src/unit/unit.test.ts b/src/unit/unit.test.ts index d2b62e8..54f8109 100644 --- a/src/unit/unit.test.ts +++ b/src/unit/unit.test.ts @@ -1598,6 +1598,66 @@ fn loops() { ) ); }); + + it("should use implementing type name for trait impl (impl Trait for Type)", () => { + const sourceCode = ` +use std::fmt; + +struct Point { x: f64, y: f64 } + +impl fmt::Display for Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {})", self.x, self.y) + } +} +`; + const results = RustMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + // Should use implementing type "Point", not trait "Display" + assert.strictEqual(results[0].name, "Point::fmt"); + }); + + it("should use inherent impl type name when no trait (impl Type)", () => { + const sourceCode = ` +struct Rectangle { width: f64, height: f64 } + +impl Rectangle { + fn area(&self) -> f64 { + self.width * self.height + } +} +`; + const results = RustMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "Rectangle::area"); + }); + + it("should handle multiple trait impl methods independently", () => { + const sourceCode = ` +use std::fmt; + +struct Counter { value: i32 } + +impl fmt::Display for Counter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Counter { + fn increment(&mut self) { + if self.value < i32::MAX { + self.value += 1; + } + } +} +`; + const results = RustMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 2); + assert.strictEqual(results[0].name, "Counter::fmt"); + assert.strictEqual(results[1].name, "Counter::increment"); + assert.strictEqual(results[1].complexity, 1); // single if + }); }); describe("Go Analyzer Additional Coverage", () => {