Skip to content

Commit 5cabeb4

Browse files
DeusDataxbsjason
andcommitted
fix(swift): index protocol method requirements as Method nodes
A Swift protocol requirement — a bodyless `func generate() -> String` inside a protocol — was absent from the graph entirely. Swift codebases are heavily protocol-driven, so the requirement is very often the declaration a reader is looking for, and "who declares generate()" had no answer. Three edits deliver it: protocol_body joins the class-body types so a protocol's members are walked at all; protocol_function_declaration joins swift_func_types, because extract_class_methods gates on that set and would otherwise walk the requirement and discard it; and both name resolvers accept the node, which has the same simple_identifier shape as function_declaration. Distilled from #613 by xbsjason. That PR also carried an enum/struct half whose two assertions fail on CI: tree-sitter-swift has no struct_declaration or enum_declaration node type (it models both as class_declaration), so the corresponding swift_class_types entries are inert and a bare enum is still labeled Class. That is a real pre-existing modelling gap, left untouched here and now documented at the dead entries rather than silently deleted. Also dropped from the original: a find_first_descendant_by_kind rescue in extract_class_methods. Removing it changes no test outcome once the function-type entry is present, so it was carrying nothing. Advances #43. Co-authored-by: xbsjason <xbsjason@gmail.com> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent 4bbc978 commit 5cabeb4

3 files changed

Lines changed: 36 additions & 4 deletions

File tree

‎internal/cbm/extract_defs.c‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,9 +745,14 @@ TSNode cbm_resolve_func_name(TSNode node, CBMLanguage lang) {
745745
}
746746

747747
/* Swift and newer tree-sitter-kotlin: function_declaration has no `name`
748-
* field; the function name is a `simple_identifier` child. */
748+
* field; the function name is a `simple_identifier` child. A Swift
749+
* protocol requirement (a bodyless `func` inside a protocol) is a
750+
* separate node type with the same shape; it is named here as well as in
751+
* resolve_method_name because swift_func_types now admits it, so it can
752+
* reach the free-function path too and would otherwise land unnamed. */
749753
if ((lang == CBM_LANG_SWIFT || lang == CBM_LANG_KOTLIN) &&
750-
strcmp(kind, "function_declaration") == 0) {
754+
(strcmp(kind, "function_declaration") == 0 ||
755+
strcmp(kind, "protocol_function_declaration") == 0)) {
751756
TSNode si = cbm_find_child_by_kind(node, "simple_identifier");
752757
if (!ts_node_is_null(si)) {
753758
return si;
@@ -4579,6 +4584,7 @@ static TSNode find_class_body(TSNode class_node, CBMLanguage lang) {
45794584
static const char *body_types[] = {"class_body",
45804585
"interface_body",
45814586
"enum_body",
4587+
"protocol_body",
45824588
"template_body",
45834589
"interface_type",
45844590
"struct_type",
@@ -4699,7 +4705,8 @@ static TSNode resolve_method_name(TSNode child, CBMLanguage lang) {
46994705
}
47004706

47014707
if ((lang == CBM_LANG_SWIFT || lang == CBM_LANG_KOTLIN) &&
4702-
strcmp(ck, "function_declaration") == 0) {
4708+
(strcmp(ck, "function_declaration") == 0 ||
4709+
strcmp(ck, "protocol_function_declaration") == 0)) {
47034710
return cbm_find_child_by_kind(child, "simple_identifier");
47044711
}
47054712

‎internal/cbm/lang_specs.c‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,16 @@ static const char *objc_var_types[] = {"declaration", NULL};
547547
static const char *objc_assign_types[] = {"assignment_expression", NULL};
548548

549549
// ==================== SWIFT ====================
550-
static const char *swift_func_types[] = {"function_declaration", "macro_declaration", NULL};
550+
// protocol_function_declaration: a protocol's method requirements. Needed here as
551+
// well as in the name resolvers — extract_class_methods gates on this set, so
552+
// without the entry the requirement is walked and then discarded.
553+
static const char *swift_func_types[] = {"function_declaration", "protocol_function_declaration",
554+
"macro_declaration", NULL};
555+
// KNOWN GAP: struct_declaration and enum_declaration are not node types in the
556+
// vendored tree-sitter-swift grammar — it models both as class_declaration — so
557+
// these two entries never match anything, and a bare Swift `enum` is labeled
558+
// Class rather than Enum. Left in place deliberately: they are the only marker
559+
// of that modelling gap, and deleting them would hide it. Tracked separately.
551560
static const char *swift_class_types[] = {"class_declaration", "protocol_declaration",
552561
"struct_declaration", "enum_declaration", NULL};
553562
static const char *swift_field_types[] = {"property_declaration", NULL};

‎tests/test_extraction.c‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,21 @@ TEST(swift_class) {
655655
PASS();
656656
}
657657

658+
TEST(swift_protocol) {
659+
/* A protocol requirement is a bodyless func inside a protocol body. Swift
660+
* codebases are heavily protocol-driven, so the requirement is very often
661+
* the declaration a reader is actually looking for — before this it was
662+
* absent from the graph entirely. */
663+
CBMFileResult *r = extract("protocol StudyRunning {\n func generate() -> String\n}\n",
664+
CBM_LANG_SWIFT, "t", "StudyRunning.swift");
665+
ASSERT_NOT_NULL(r);
666+
ASSERT_FALSE(r->has_error);
667+
ASSERT(has_def(r, "Interface", "StudyRunning"));
668+
ASSERT(has_def(r, "Method", "generate"));
669+
cbm_free_result(r);
670+
PASS();
671+
}
672+
658673
/* --- Kotlin --- */
659674
TEST(kotlin_function) {
660675
CBMFileResult *r = extract("fun greet(name: String): String = \"Hello $name\"\nfun main() { "
@@ -5451,6 +5466,7 @@ SUITE(extraction) {
54515466
RUN_TEST(csharp_class);
54525467
RUN_TEST(csharp_interface);
54535468
RUN_TEST(swift_class);
5469+
RUN_TEST(swift_protocol);
54545470
RUN_TEST(kotlin_function);
54555471
RUN_TEST(kotlin_class);
54565472
RUN_TEST(scala_function);

0 commit comments

Comments
 (0)