Skip to content

Commit aefd2a1

Browse files
authored
Merge pull request DeusData#2008 from CaptainMittens/fix/decorator-arg-scan-limit
fix(routes): find a route path wherever it sits in a decorator's arguments
2 parents 4d8ac9e + c36b4fb commit aefd2a1

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

‎internal/cbm/extract_defs.c‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1450,8 +1450,12 @@ static const char *find_route_path_literal(CBMArena *a, TSNode node, const char
14501450

14511451
// Extract route path from decorator arguments (first string that starts with /).
14521452
static const char *extract_route_path_from_args(CBMArena *a, TSNode args, const char *source) {
1453+
/* Every argument is checked. Java and Kotlin put no order on annotation
1454+
* attributes, so `path` can sit anywhere in the list. Stopping early left
1455+
* a real route unread and formed no Route node. Each argument's own
1456+
* subtree walk stays bounded by find_route_path_literal below. */
14531457
uint32_t nc = ts_node_named_child_count(args);
1454-
for (uint32_t ai = 0; ai < nc && ai < DECORATOR_SCAN_LIMIT; ai++) {
1458+
for (uint32_t ai = 0; ai < nc; ai++) {
14551459
TSNode arg = ts_node_named_child(args, ai);
14561460
/* Spring/Kotlin frequently uses named or array-valued annotation args:
14571461
* @RequestMapping(value = ["/internal/v1"])

‎tests/test_edge_types_probe.c‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,30 @@ TEST(handles_spring_java) {
416416
PASS();
417417
}
418418

419+
/* Spring (Java) — the path attribute may sit anywhere in the annotation.
420+
* Java puts no order on annotation attributes, so `path` after `name`,
421+
* `produces` and `consumes` is ordinary source. The argument scan stopped
422+
* after the third attribute, so the path was never read and no Route node
423+
* formed. A HANDLES count alone cannot catch that, because the class-level
424+
* @RequestMapping still produces one route on its own. */
425+
TEST(handles_spring_java_path_attribute_fourth) {
426+
static const char *routes[] = {"/api/orders", NULL};
427+
static const EtFile f[] = {
428+
{"OrderController.java",
429+
"package com.example;\n\n"
430+
"import org.springframework.web.bind.annotation.RequestMapping;\n"
431+
"import org.springframework.web.bind.annotation.GetMapping;\n\n"
432+
"@RequestMapping(\"/api\")\npublic class OrderController {\n"
433+
" @GetMapping(name = \"listOrders\",\n"
434+
" produces = \"application/json\",\n"
435+
" consumes = \"application/json\",\n"
436+
" path = \"/orders\")\n"
437+
" public String listOrders() {\n"
438+
" return \"orders\";\n }\n}\n"}};
439+
ASSERT_TRUE(et_routes_exact(f, 1, routes));
440+
PASS();
441+
}
442+
419443
/* Spring (Kotlin) — same prefix contract, including Kotlin's named array form
420444
* for class-level RequestMapping values. */
421445
TEST(handles_spring_kotlin) {
@@ -1578,6 +1602,7 @@ SUITE(edge_types_probe) {
15781602
RUN_TEST(handles_fastify_js);
15791603
RUN_TEST(handles_gin_go);
15801604
RUN_TEST(handles_spring_java);
1605+
RUN_TEST(handles_spring_java_path_attribute_fourth);
15811606
RUN_TEST(handles_spring_kotlin);
15821607
RUN_TEST(handles_jaxrs_java);
15831608
RUN_TEST(handles_aspnet_csharp);

0 commit comments

Comments
 (0)