Skip to content
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
f7b084e
Added new metadata type, extracted data from cfg and the function.
AlonBilman Mar 18, 2025
3151ea6
extracting all the data for issue #94 , tested the extraction with gi…
AlonBilman Mar 18, 2025
ca084e1
added the metadata to the page
AlonBilman Mar 18, 2025
7a7b13f
Updated .md files (changelog and readme)
AlonBilman Mar 19, 2025
2ae4d60
linting- commit in order to merge
AlonBilman Mar 23, 2025
d5bbffb
check and update lint
Bennahmias Mar 26, 2025
a2ba7d5
Trying to find a way to avoid fetching twice and to make the relevant…
AlonBilman Mar 27, 2025
7618ad8
Merge remote-tracking branch 'origin/main' into issue#94
AlonBilman Apr 2, 2025
d675eac
Added function name extraction in function-utils.ts
AlonBilman Apr 2, 2025
6e6d675
Add: functionDetils.test.ts file that test for now the extractFunctio…
Bennahmias Apr 2, 2025
e944b01
Merge remote-tracking branch 'origin/issue#94' into issue#94_testing
Bennahmias Apr 2, 2025
a71484b
Fix: update import path for extractFunctionName and add console log f…
Bennahmias Apr 2, 2025
34e3ae6
Refactor function name extraction to improve type handling and add su…
AlonBilman Apr 4, 2025
328d86d
Fixed a bug in the TypeScript generator's function name extraction.
AlonBilman Apr 4, 2025
dcea710
added documentation
AlonBilman Apr 4, 2025
69bf1a4
Refactor: update tests for extractFunctionName
Bennahmias Apr 5, 2025
0d3f03e
Merge remote-tracking branch 'origin/issue#94' into issue#94_testing
Bennahmias Apr 5, 2025
c279feb
simplify anonymous function naming
AlonBilman Apr 5, 2025
fac3bef
change the test suites
Bennahmias Apr 5, 2025
ce19dd5
Merge remote-tracking branch 'origin/issue#94' into issue#94_testing
Bennahmias Apr 5, 2025
4d7f20f
fix: add some test cases
Bennahmias Apr 5, 2025
542004b
test: add new function tests
Bennahmias Apr 5, 2025
5dc7ce2
remove comments from tests
Bennahmias Apr 5, 2025
dc4457f
Merge remote-tracking branch 'origin/main' into issue#94
AlonBilman Apr 14, 2025
b73437c
add experimental metadata display and control panel for function anal…
AlonBilman Apr 14, 2025
7253af7
Adjusting styles for dark/light modes
AlonBilman Apr 15, 2025
f69336f
Refactor function name extraction to return "<Anonymous>" for anonymo…
Bennahmias Apr 17, 2025
26c9883
refactor: separate all languages into individual files without changi…
AlonBilman Apr 23, 2025
1768167
Merge branch 'main' into issue#94
AlonBilman Apr 23, 2025
c17b84c
feat(parser): enhance C++ function name extraction for operator overl…
AlonBilman Apr 23, 2025
52c72f7
test: add tests for extracting function names from Go literals and sh…
AlonBilman Apr 23, 2025
8c74c99
refactor(tests): migrate from bun to vitest and update imports
Bennahmias Apr 24, 2025
89a9f51
extract var name from function assignment using Tree-sitter
AlonBilman Apr 24, 2025
051ccc6
Merge remote-tracking branch 'origin/issue#94_testing' into issue#94
AlonBilman Apr 24, 2025
8adbcfd
refactor: rename extractNameByNodeName to extractNameByNodeType and u…
AlonBilman Apr 24, 2025
9880873
refactor: replaced findNameInParentHierarchy with a query-based appro…
AlonBilman Apr 25, 2025
d145111
delete snapshot changes. (will be added if needed)
AlonBilman May 4, 2025
3ab9247
Improved render style to prevent sliding window from breaking on brow…
AlonBilman May 4, 2025
009f53a
feat: add Graph rendering with CFG-metadata options only
AlonBilman May 4, 2025
e6c8172
Merge remote-tracking branch 'origin/main' into issue#94
AlonBilman May 8, 2025
607b7fe
CHANGELOG with new features
AlonBilman May 10, 2025
2469d6d
Revert unnecessary changes. mb.
AlonBilman May 10, 2025
41ac697
Revert unnecessary changes. MB.
AlonBilman May 10, 2025
fd7aa24
Merge remote-tracking branch 'origin/main' into issue#94
AlonBilman May 10, 2025
421878f
Added a few failing tests that should pass.
tmr232 May 13, 2025
ffbae88
Merge remote-tracking branch 'origin/main' into issue#94
AlonBilman Aug 3, 2025
dcd0bd9
cange some design
Bennahmias Aug 7, 2025
6795204
Refactor function name extraction to use a mapping for supported lang…
Bennahmias Aug 10, 2025
aafda36
Enhance TypeScript function name extraction with new query structure …
AlonBilman Aug 14, 2025
d5a415e
Refactor TypeScript function name extraction tests and remove depreca…
AlonBilman Aug 16, 2025
546d8da
dummy commit.
AlonBilman Aug 17, 2025
65eb0a0
Refactor TypeScript function name extraction and tests
AlonBilman Aug 17, 2025
c570bd3
fix: resolve circular dependency
AlonBilman Aug 18, 2025
491c11e
refactor : enhance Python function name extraction and edited tests.
AlonBilman Aug 18, 2025
8ff7179
refactor: reorganize imports
AlonBilman Aug 18, 2025
4881842
refactor: streamline function name extraction and improve test cases
AlonBilman Aug 19, 2025
a87245f
More small refactors and Go is done.
AlonBilman Aug 19, 2025
cdaae1d
refactor: simplify method definition queries and enhance test cases f…
AlonBilman Aug 20, 2025
e461ea4
Oops forgot to lint..
AlonBilman Aug 20, 2025
f372e4c
delete similar tests and open the cpp test file
Bennahmias Aug 20, 2025
16eb3f1
test(cpp): add function name extraction tests and uncover major bugs
AlonBilman Aug 20, 2025
5da022e
refactor(cpp): finished non-arrow function names after long fight in …
AlonBilman Aug 21, 2025
071fa8c
refactor(c++): update C++ function name extraction and tests - small …
AlonBilman Aug 25, 2025
a409c22
cpp: finished extraction name logic.
AlonBilman Aug 26, 2025
cd10232
delete redundant Go and C++ function extraction tests
AlonBilman Aug 26, 2025
be1f075
refactor small things regarding extractions , lint + tests are passin…
AlonBilman Aug 26, 2025
96f7cf9
change example
AlonBilman Aug 27, 2025
cf9a808
Refactor app.svelte to display "<anonymous>" when no name has been ex…
AlonBilman Aug 29, 2025
488d200
Update tests : replace "<anonymous>" with undefined
AlonBilman Aug 29, 2025
40cef6d
Refactor tests in extractNameTypescript.test.ts
AlonBilman Aug 31, 2025
b731404
Refactor Python tests
AlonBilman Aug 31, 2025
c05ddf2
Refactor C ;Python ;Typescript tests
AlonBilman Aug 31, 2025
734d70d
Merge branch 'issue#94' of https://github.com/AlonBilman/function-gra…
AlonBilman Sep 1, 2025
e0603a7
Refactor Go tests
AlonBilman Sep 1, 2025
a586e5d
Refactor C++ test cases
AlonBilman Sep 1, 2025
a5ca535
fix PR changes
Bennahmias Sep 7, 2025
0aebc93
removed a test case for Go
AlonBilman Sep 7, 2025
baab71d
Refactor findVariableBinding in go
AlonBilman Sep 7, 2025
555194f
add comments to binding functions
AlonBilman Sep 7, 2025
2330f49
Update CONTRIBUTORS.md
AlonBilman Sep 7, 2025
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

## [Unreleased]

### Added

- Function name extraction with support for multiple programming languages.
- Unit tests for function name extraction, covering various structures and languages.
- Frontend logic in `render/src/App.svelte` to extract and display metadata based on render type.
- Display of both CFG and function metadata in the GitHub render view, and CFG metadata in the Graph render view.

## [0.0.16] - 2025-05-07

### Added
Expand Down
17 changes: 17 additions & 0 deletions src/control-flow/cfg-c.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
type StatementHandlers,
} from "./generic-cfg-builder.ts";
import { treeSitterNoNullNodes } from "./hacks.ts";
import { extractTaggedValueFromTreeSitterQuery } from "./query-utils.ts";
import { buildSwitch, collectCases } from "./switch-utils.ts";

export const cLanguageDefinition = {
Expand Down Expand Up @@ -166,3 +167,19 @@ function processSwitchlike(switchSyntax: SyntaxNode, ctx: Context): BasicBlock {

return blockHandler.update({ entry: headNode, exit: mergeNode });
}

const functionQuery = {
functionDeclarator: `(function_declarator
declarator:(identifier)@name)`,

tag: "name",
};

export function extractCFunctionName(func: SyntaxNode): string | undefined {
const name = extractTaggedValueFromTreeSitterQuery(
func,
functionQuery.functionDeclarator,
functionQuery.tag,
);
return name.length > 1 ? undefined : name[0];
}
91 changes: 91 additions & 0 deletions src/control-flow/cfg-cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
type StatementHandlers,
} from "./generic-cfg-builder.ts";
import { pairwise, zip } from "./itertools.ts";
import { extractTaggedValueFromTreeSitterQuery } from "./query-utils.ts";

export const cppLanguageDefinition = {
wasmPath: treeSitterCpp,
Expand Down Expand Up @@ -148,3 +149,93 @@ function processTryStatement(trySyntax: SyntaxNode, ctx: Context): BasicBlock {
});
});
}

const functionQuery = {
functionDeclarator: `
(function_declarator
declarator: [
(identifier) @name
(type_identifier) @name
(destructor_name) @name
(operator_name) @name
(operator_cast) @name
(field_identifier) @name
(qualified_identifier
name: [
(identifier) @name
(type_identifier) @name
(destructor_name) @name
(operator_name) @name
(operator_cast) @name
])
])
`,
functionDefinitionOperator: `
(function_definition
declarator: (operator_cast
(_) @type))

(function_definition
declarator: (qualified_identifier
name: (operator_cast
(_) @type)))`,

name: "name",

type: "type",
};

/**
* Get the function_declarator node for a function_definition.
* Uses descendantsOfType to find it directly, even if wrapped
* in pointer/reference/parenthesized declarators.
*/
function getFunctionDeclarator(funcDef: SyntaxNode): SyntaxNode | null {
const body = funcDef.childForFieldName("body");
const end = body ? body.startPosition : funcDef.endPosition;

const nodes = funcDef.descendantsOfType(
"function_declarator",
funcDef.startPosition,
end,
);

for (const node of nodes) {
const decl = node?.childForFieldName("declarator");
if (
decl &&
(decl.type === "identifier" ||
decl.type === "operator_name" ||
decl.type === "operator_cast" ||
decl.type === "destructor_name" ||
decl.type === "qualified_identifier" ||
decl.type === "type_identifier" ||
decl.type === "field_identifier")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

) {
return node;
}
}

return null;
}

export function extractCppFunctionName(func: SyntaxNode): string | undefined {
if (func.type !== "function_definition") return undefined; //Just for now...

const declarator = getFunctionDeclarator(func);
const name = declarator
? extractTaggedValueFromTreeSitterQuery(
declarator,
functionQuery.functionDeclarator,
functionQuery.name,
)[0]
: undefined;
if (name) return name;

const type = extractTaggedValueFromTreeSitterQuery(
func,
functionQuery.functionDefinitionOperator,
functionQuery.type,
)[0];
return type ? `operator ${type}` : undefined;
}
111 changes: 111 additions & 0 deletions src/control-flow/cfg-go.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
type StatementHandlers,
} from "./generic-cfg-builder";
import { treeSitterNoNullNodes } from "./hacks.ts";
import { extractTaggedValueFromTreeSitterQuery } from "./query-utils.ts";
import { type SwitchOptions, buildSwitch, collectCases } from "./switch-utils";

export const goLanguageDefinition = {
Expand Down Expand Up @@ -419,3 +420,113 @@ function processSwitchlike(

return blockHandler.update({ entry: headNode, exit: mergeNode });
}

const functionQuery = {
functionDeclaration: `(function_declaration
name :(identifier) @name)`,

methodDeclaration: `(method_declaration
name: (field_identifier) @name)`,

shortVarDeclaration: `(short_var_declaration
left: (expression_list (identifier) @name))`,

varSpec: `(var_spec
name: (identifier) @name)`,

assignmentStatement: `(assignment_statement
left: (expression_list
[
(identifier) @name
(selector_expression) @name
]))`,

name: "name",
};

function findVariableBinding(func: SyntaxNode): string {
const parent = func.parent;
const anonymous = "<anonymous>";
if (!parent) return anonymous;

// Walk the right-hand expression list and find the index of *this* func literal.
// I compare by node id to be safe — same node, same id.
const findFuncIndex = (
funcNode: SyntaxNode,
right: SyntaxNode,
): number | null => {
for (let i = 0; i < right.namedChildCount; i++) {
const child = right.namedChild(i);
if (child?.type === "func_literal" && child.id === funcNode.id) return i;
}
return null;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

};

// We run the left query -> get names[], locate our func literal on the right -> get index,
// then names[index] is the binding.
// If nothing matches, return "<anonymous>".
const bindFromPair = (
node: SyntaxNode,
leftPattern: string,
rightField: "right" | "value" = "right",
): string => {
const left = extractTaggedValueFromTreeSitterQuery(
node,
leftPattern,
functionQuery.name,
);
const right = node.childForFieldName(rightField);
if (!right) return anonymous;

const foundIndex = findFuncIndex(func, right);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We don't care that we "found" the index, we want to know what it represents.

return foundIndex !== null ? (left[foundIndex] ?? anonymous) : anonymous;
};

// := short var declaration
if (parent.parent?.type === "short_var_declaration") {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Why not a switch-case here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on it

return bindFromPair(
parent.parent,
functionQuery.shortVarDeclaration,
"right",
);
}

// = plain assignment ...
if (parent.parent?.type === "assignment_statement") {
return bindFromPair(
parent.parent,
functionQuery.assignmentStatement,
"right",
);
}

// var x, y = ..., func(){}, ...
// Same idea, but Go’s var spec uses "value".
if (parent.parent?.type === "var_spec") {
return bindFromPair(parent.parent, functionQuery.varSpec, "value");
}

// If we got here, we didn’t find a binding in the supported contexts.
return anonymous;
}

export function extractGoFunctionName(func: SyntaxNode): string | undefined {
switch (func.type) {
case "function_declaration":
return extractTaggedValueFromTreeSitterQuery(
func,
functionQuery.functionDeclaration,
functionQuery.name,
)[0];
case "method_declaration":
return extractTaggedValueFromTreeSitterQuery(
func,
functionQuery.methodDeclaration,
functionQuery.name,
)[0];
case "func_literal":
return findVariableBinding(func);
default:
return undefined;
}
}
19 changes: 19 additions & 0 deletions src/control-flow/cfg-python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
type StatementHandlers,
} from "./generic-cfg-builder.ts";
import { maybe, zip } from "./itertools.ts";
import { extractTaggedValueFromTreeSitterQuery } from "./query-utils.ts";

export const pythonLanguageDefinition = {
wasmPath: treeSitterPython,
Expand Down Expand Up @@ -624,3 +625,21 @@ function processWhileStatement(

return matcher.update({ entry: condBlock.entry, exit: exitNode });
}

const functionQuery = {
functionDefinition: `(function_definition
name :(identifier)@name)`,

tag: "name",
};

export function extractPythonFunctionName(
func: SyntaxNode,
): string | undefined {
const name = extractTaggedValueFromTreeSitterQuery(
func,
functionQuery.functionDefinition,
functionQuery.tag,
);
return name.length > 1 ? undefined : name[0];
Comment thread
AlonBilman marked this conversation as resolved.
Outdated
}
Loading