mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-29 14:49:36 +08:00
fix(erlang): a comment in an argument list no longer counts as an argument
Since PR #1615 made arity part of an Erlang function's identity, arity is counted from the argument list's named children. tree-sitter reports a comment as a named child, so a comment at the top level of a parameter or argument list raised the count by one. A call written plain( % note followed by two arguments was looked up as plain/3 and linked to nothing, a definition with a comment between its parameters was indexed one arity too high, and the MFA list of spawn(M, f, [A, B]) with a comment between A and B gave f/3. A comment nested deeper, inside a tuple, a record or a list argument, was never affected. The three counts now go through one namedArgCount helper that leaves comments out: a clause's and a spec's arity, a call site's arity, and the MFA list's. Conflict resolution: the import block of tree-sitter.ts moved on main since the PR; main's imports are kept, with namedArgCount added. Validation: the new test fails on main (its fixture gets no call edge at all) and passes here. A/B against main: rebar3 97e9367 gains 2 edges (rebar_compiler.erl:403 and rebar_release_SUITE.erl:247, both calls whose argument lists hold a comment, both checked against the source), 0 removed, nodes unchanged; cowboy 6475600 and ranch 7ec436d are byte-identical, as are the controls express and flask. Erlang has no kernel extractor, so there is no parity to run. Index CPU on rebar3, median of 3 interleaved: 9.9 s on main, 9.3 s here. Original PR #1619 by @Dshuishui. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Colby Mchenry
co-authored by
Claude Opus 5.5
parent
90c5dc6fc9
commit
44adef821b
@@ -1,5 +1,10 @@
|
||||
import type { Node as SyntaxNode } from 'web-tree-sitter';
|
||||
import { getNodeText, getChildByField, getPrecedingDocstring } from '../tree-sitter-helpers';
|
||||
import {
|
||||
getNodeText,
|
||||
getChildByField,
|
||||
getPrecedingDocstring,
|
||||
namedArgCount,
|
||||
} from '../tree-sitter-helpers';
|
||||
import type { LanguageExtractor, ExtractorContext } from '../tree-sitter-types';
|
||||
|
||||
// Node names follow the vendored WhatsApp/tree-sitter-erlang grammar (0.19,
|
||||
@@ -95,10 +100,9 @@ function moduleExports(node: SyntaxNode, source: string, filePath: string): Set<
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Argument count of a clause/sig: the `args` (expr_args) field's named-child count. */
|
||||
/** Argument count of a clause/sig: the `args` (expr_args) field's arguments. */
|
||||
function nodeArity(withArgs: SyntaxNode): number {
|
||||
const args = getChildByField(withArgs, 'args');
|
||||
return args ? args.namedChildCount : 0;
|
||||
return namedArgCount(getChildByField(withArgs, 'args'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -130,6 +130,19 @@ function cleanCommentMarkers(comment: string): string {
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of ARGUMENTS in an `args` node — its named children minus comments.
|
||||
*
|
||||
* tree-sitter reports `comment` as a NAMED child, so a comment written at the
|
||||
* top level of a parameter or argument list (`f(A, % why\n B)`) inflates a
|
||||
* plain `namedChildCount`. Anywhere that count is an arity — and arity is part
|
||||
* of an Erlang function's identity (#1610) — the comment must not be counted.
|
||||
*/
|
||||
export function namedArgCount(argsNode: SyntaxNode | null | undefined): number {
|
||||
if (!argsNode) return 0;
|
||||
return argsNode.namedChildren.filter((c) => c.type !== 'comment').length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the docstring/comment preceding a node
|
||||
*
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
UnresolvedReference,
|
||||
} from '../types';
|
||||
import { getParser, detectLanguage, isLanguageSupported, isFileLevelOnlyLanguage } from './grammars';
|
||||
import { NodeIdAllocator, getNodeText, getChildByField, getPrecedingDocstring, BUILTIN_TYPE_NAMES } from './tree-sitter-helpers';
|
||||
import { NodeIdAllocator, getNodeText, getChildByField, getPrecedingDocstring, BUILTIN_TYPE_NAMES, namedArgCount } from './tree-sitter-helpers';
|
||||
import { FN_REF_SPECS, captureFnRefCandidates, goScopedFnRefScopes, type FnRefSpec, type FnRefCandidate } from './function-ref';
|
||||
import { isGeneratedFile, isMinifiedContent } from './generated-detection';
|
||||
import type { LanguageExtractor, ExtractorContext } from './tree-sitter-types';
|
||||
@@ -5405,8 +5405,7 @@ export class TreeSitterExtractor {
|
||||
}
|
||||
// Arity from the call site's own argument list — part of the callee's
|
||||
// identity, and what disambiguates `f/1` from `f/2` (#1610).
|
||||
const callArgsNode = getChildByField(node, 'args');
|
||||
const callArity = callArgsNode ? callArgsNode.namedChildCount : 0;
|
||||
const callArity = namedArgCount(getChildByField(node, 'args'));
|
||||
this.unresolvedReferences.push({
|
||||
fromNodeId: callerId,
|
||||
referenceName: `${calleeName}/${callArity}`,
|
||||
@@ -5473,7 +5472,7 @@ export class TreeSitterExtractor {
|
||||
// qualified matcher then resolves it only when the module
|
||||
// defines exactly one arity of that name.
|
||||
const mfaList = argExprs[i + 2];
|
||||
const arityTail = mfaList?.type === 'list' ? `/${mfaList.namedChildCount}` : '';
|
||||
const arityTail = mfaList?.type === 'list' ? `/${namedArgCount(mfaList)}` : '';
|
||||
this.unresolvedReferences.push({
|
||||
fromNodeId: callerId,
|
||||
referenceName: (isLocalModule ? erlAtom(f) : `${erlAtom(m)}::${erlAtom(f)}`) + arityTail,
|
||||
|
||||
Reference in New Issue
Block a user