Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/metricsAnalyzer/languages/complexityHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,35 @@ export function hasLabelChild(node: Parser.SyntaxNode, labelTypes: string | read
}
return typeof labelTypes === "string" ? childType === labelTypes : labelTypes.includes(childType);
}

/**
* Walks up from `node` to find the name of the nearest enclosing type
* declaration (class, struct, interface, record, or enum), returning `null`
* if no such ancestor exists (e.g. top-level local functions).
*
* Shared by the C# and Java analyzers, which both identify the enclosing
* type by walking `node.parent` until a type-declaration node type is found,
* then reading its `name` field.
*
* @param node - The syntax node to start searching from (typically a function/method declaration)
* @param typeDeclarationTypes - Node type name(s) that represent a type declaration
* @param sourceText - The full source text, used to extract the name substring
* @returns The enclosing type name, or null if none found
*/
export function findEnclosingTypeName(
node: Parser.SyntaxNode,
typeDeclarationTypes: ReadonlySet<string>,
sourceText: string
): string | null {
let parent = node.parent;
while (parent) {
if (typeDeclarationTypes.has(parent.type)) {
const nameNode = parent.childForFieldName("name");
if (nameNode) {
return sourceText.substring(nameNode.startIndex, nameNode.endIndex);
}
}
parent = parent.parent;
}
return null;
}
14 changes: 2 additions & 12 deletions src/metricsAnalyzer/languages/csharpAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import Parser from "tree-sitter";
import CSharp from "tree-sitter-c-sharp";
import { isOutermostInSameOperatorChain, getBinaryLogicalOperator } from "./complexityHelpers";
import { isOutermostInSameOperatorChain, getBinaryLogicalOperator, findEnclosingTypeName } from "./complexityHelpers";

// Module-level singleton: parser initialization is expensive, so we reuse one instance per language.
const _parser = new Parser();
Expand Down Expand Up @@ -296,17 +296,7 @@ export class CSharpMetricsAnalyzer {
* @returns The enclosing type name, or null if none found
*/
private getEnclosingTypeName(node: Parser.SyntaxNode): string | null {
let parent = node.parent;
while (parent) {
if (CSharpMetricsAnalyzer.TYPE_DECLARATION_TYPES.has(parent.type)) {
const nameNode = parent.childForFieldName("name");
if (nameNode) {
return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex);
}
}
parent = parent.parent;
}
return null;
return findEnclosingTypeName(node, CSharpMetricsAnalyzer.TYPE_DECLARATION_TYPES, this.sourceText);
}

/**
Expand Down
20 changes: 3 additions & 17 deletions src/metricsAnalyzer/languages/javaAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import Parser from "tree-sitter";
import Java from "tree-sitter-java";
import { isOutermostInSameOperatorChain, getBinaryLogicalOperator } from "./complexityHelpers";
import { isOutermostInSameOperatorChain, getBinaryLogicalOperator, findEnclosingTypeName } from "./complexityHelpers";

// Module-level singleton: parser initialization is expensive, so we reuse one instance per language.
const _parser = new Parser();
Expand Down Expand Up @@ -201,24 +201,10 @@ export class JavaMetricsAnalyzer {
? this.sourceText.substring(nameNode.startIndex, nameNode.endIndex)
: "<anonymous>";

// Walk up the AST to find the enclosing class, interface, enum, or record name
let parent = node.parent;
while (parent) {
if (JavaMetricsAnalyzer.TYPE_DECLARATION_TYPES.has(parent.type)) {
const classNameNode = parent.childForFieldName("name");
if (classNameNode) {
const className = this.sourceText.substring(
classNameNode.startIndex,
classNameNode.endIndex
);
return `${className}.${methodName}`;
}
}
parent = parent.parent;
}
const className = findEnclosingTypeName(node, JavaMetricsAnalyzer.TYPE_DECLARATION_TYPES, this.sourceText);

/* c8 ignore next */
return methodName;
return className ? `${className}.${methodName}` : methodName;
}

/**
Expand Down
Loading