Skip to content

Commit b7ba394

Browse files
author
Your Name
committed
feat(extraction): entry point detection for C#/Java class methods
Previously only JS/TS exports and lowercase 'main' were recognized as entry points, causing 0 execution flows for C#/Java repos. Changes: - Case-insensitive main detection (strcasecmp) — fixes C# 'Main' and Java 'main' in both extract_func_def and push_method_def paths - C# Windows Service lifecycle: OnStart, OnStartImpl, Run, Execute, Configure, ConfigureServices - C# ASP.NET decorators: [HttpGet], [HttpPost], [Route], [ApiController] - C# test decorators: [TestMethod], [Fact], [Test] - Java patterns: start, configure, init, run, handle - Java Spring/JAX-RS: @RequestMapping, @GetMapping, @PostMapping, etc. - Java JUnit/lifecycle: @OverRide, @test, @scheduled, @bean Critical fix: push_method_def() (class methods) was missing entry point detection entirely — only extract_func_def() (standalone functions) had it. Tested: C# monolith 1→69 flows, Java/Vert.x repo 0→300 flows, C# desktop app 2→280 flows + 33 routes discovered.
1 parent 689050f commit b7ba394

1 file changed

Lines changed: 116 additions & 2 deletions

File tree

internal/cbm/extract_defs.c

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "tree_sitter/api.h" // TSNode, ts_node_*
66
#include <stdint.h> // uint32_t
77
#include <string.h>
8+
#include <strings.h> /* strcasecmp */
89
#include <ctype.h>
910

1011
// Field name lengths for ts_node_child_by_field_name() calls.
@@ -1184,11 +1185,72 @@ static void extract_func_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
11841185
}
11851186
}
11861187

1187-
// main is always an entry point
1188-
if (strcmp(name, "main") == 0) {
1188+
// main/Main is always an entry point (case-insensitive for C#/Java)
1189+
if (strcasecmp(name, "main") == 0) {
11891190
def.is_entry_point = true;
11901191
}
11911192

1193+
// C# entry point detection: Windows Service lifecycle, ASP.NET controllers
1194+
if (ctx->language == CBM_LANG_CSHARP && !def.is_entry_point) {
1195+
// Windows Service lifecycle entry points
1196+
if (strcmp(name, "OnStart") == 0 || strcmp(name, "OnStartImpl") == 0 ||
1197+
strcmp(name, "OnStop") == 0 || strcmp(name, "OnStopImpl") == 0 ||
1198+
strcmp(name, "Run") == 0 || strcmp(name, "Execute") == 0 ||
1199+
strcmp(name, "Configure") == 0 || strcmp(name, "ConfigureServices") == 0) {
1200+
def.is_entry_point = true;
1201+
}
1202+
// ASP.NET controller decorators: [HttpGet], [HttpPost], [Route], etc.
1203+
if (!def.is_entry_point && def.decorators) {
1204+
for (const char **d = def.decorators; *d; d++) {
1205+
if (strstr(*d, "HttpGet") || strstr(*d, "HttpPost") ||
1206+
strstr(*d, "HttpPut") || strstr(*d, "HttpDelete") ||
1207+
strstr(*d, "HttpPatch") || strstr(*d, "Route") ||
1208+
strstr(*d, "ApiController") || strstr(*d, "Authorize")) {
1209+
def.is_entry_point = true;
1210+
break;
1211+
}
1212+
}
1213+
}
1214+
// Test entry points: [TestMethod], [Fact], [Test], [SetUp]
1215+
if (!def.is_entry_point && def.decorators) {
1216+
for (const char **d = def.decorators; *d; d++) {
1217+
if (strstr(*d, "TestMethod") || strstr(*d, "Fact") ||
1218+
strstr(*d, "Test") || strstr(*d, "SetUp") ||
1219+
strstr(*d, "TestInitialize")) {
1220+
def.is_entry_point = true;
1221+
break;
1222+
}
1223+
}
1224+
}
1225+
}
1226+
1227+
// Java entry point detection: Spring Boot, Vert.x, JAX-RS, JUnit
1228+
if (ctx->language == CBM_LANG_JAVA && !def.is_entry_point) {
1229+
// Vert.x lifecycle and common server patterns
1230+
if (strcmp(name, "start") == 0 || strcmp(name, "configure") == 0 ||
1231+
strcmp(name, "init") == 0 || strcmp(name, "run") == 0 ||
1232+
strcmp(name, "handle") == 0) {
1233+
def.is_entry_point = true;
1234+
}
1235+
// Spring/JAX-RS/JUnit decorators
1236+
if (!def.is_entry_point && def.decorators) {
1237+
for (const char **d = def.decorators; *d; d++) {
1238+
if (strstr(*d, "RequestMapping") || strstr(*d, "GetMapping") ||
1239+
strstr(*d, "PostMapping") || strstr(*d, "PutMapping") ||
1240+
strstr(*d, "DeleteMapping") || strstr(*d, "PatchMapping") ||
1241+
strstr(*d, "Endpoint") || strstr(*d, "EventHandler") ||
1242+
strstr(*d, "Scheduled") || strstr(*d, "Bean") ||
1243+
strstr(*d, "Override") || strstr(*d, "Test") ||
1244+
strstr(*d, "GET") || strstr(*d, "POST") ||
1245+
strstr(*d, "PUT") || strstr(*d, "DELETE") ||
1246+
strstr(*d, "Path") || strstr(*d, "Consumes")) {
1247+
def.is_entry_point = true;
1248+
break;
1249+
}
1250+
}
1251+
}
1252+
}
1253+
11921254
cbm_defs_push(&ctx->result->defs, a, def);
11931255
}
11941256

@@ -1658,6 +1720,58 @@ static void push_method_def(CBMExtractCtx *ctx, TSNode child, const char *class_
16581720
def.complexity = cbm_count_branching(child, spec->branching_node_types);
16591721
}
16601722

1723+
// Entry point detection for class methods (same rules as extract_func_def)
1724+
// Case-insensitive "main" check
1725+
if (strcasecmp(name, "main") == 0) {
1726+
def.is_entry_point = true;
1727+
}
1728+
1729+
// C# entry point detection: Windows Service lifecycle, ASP.NET controllers
1730+
if (ctx->language == CBM_LANG_CSHARP && !def.is_entry_point) {
1731+
if (strcmp(name, "OnStart") == 0 || strcmp(name, "OnStartImpl") == 0 ||
1732+
strcmp(name, "OnStop") == 0 || strcmp(name, "OnStopImpl") == 0 ||
1733+
strcmp(name, "Run") == 0 || strcmp(name, "Execute") == 0 ||
1734+
strcmp(name, "Configure") == 0 || strcmp(name, "ConfigureServices") == 0) {
1735+
def.is_entry_point = true;
1736+
}
1737+
if (!def.is_entry_point && def.decorators) {
1738+
for (const char **d = def.decorators; *d; d++) {
1739+
if (strstr(*d, "HttpGet") || strstr(*d, "HttpPost") ||
1740+
strstr(*d, "HttpPut") || strstr(*d, "HttpDelete") ||
1741+
strstr(*d, "HttpPatch") || strstr(*d, "Route") ||
1742+
strstr(*d, "ApiController") || strstr(*d, "Authorize")) {
1743+
def.is_entry_point = true;
1744+
break;
1745+
}
1746+
}
1747+
}
1748+
}
1749+
1750+
// Java entry point detection
1751+
if (ctx->language == CBM_LANG_JAVA && !def.is_entry_point) {
1752+
if (strcmp(name, "start") == 0 || strcmp(name, "configure") == 0 ||
1753+
strcmp(name, "init") == 0 || strcmp(name, "run") == 0 ||
1754+
strcmp(name, "handle") == 0) {
1755+
def.is_entry_point = true;
1756+
}
1757+
if (!def.is_entry_point && def.decorators) {
1758+
for (const char **d = def.decorators; *d; d++) {
1759+
if (strstr(*d, "RequestMapping") || strstr(*d, "GetMapping") ||
1760+
strstr(*d, "PostMapping") || strstr(*d, "PutMapping") ||
1761+
strstr(*d, "DeleteMapping") || strstr(*d, "PatchMapping") ||
1762+
strstr(*d, "Endpoint") || strstr(*d, "EventHandler") ||
1763+
strstr(*d, "Scheduled") || strstr(*d, "Bean") ||
1764+
strstr(*d, "Override") || strstr(*d, "Test") ||
1765+
strstr(*d, "GET") || strstr(*d, "POST") ||
1766+
strstr(*d, "PUT") || strstr(*d, "DELETE") ||
1767+
strstr(*d, "Path") || strstr(*d, "Consumes")) {
1768+
def.is_entry_point = true;
1769+
break;
1770+
}
1771+
}
1772+
}
1773+
}
1774+
16611775
cbm_defs_push(&ctx->result->defs, a, def);
16621776
}
16631777

0 commit comments

Comments
 (0)