Skip to content

Commit 5e9c633

Browse files
authored
Merge pull request #1763 from DeusData/feat/swift-protocol-methods
fix(swift): index protocol method requirements as Method nodes
2 parents edfc2de + 5cabeb4 commit 5e9c633

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() { "
@@ -5545,6 +5560,7 @@ SUITE(extraction) {
55455560
RUN_TEST(csharp_class);
55465561
RUN_TEST(csharp_interface);
55475562
RUN_TEST(swift_class);
5563+
RUN_TEST(swift_protocol);
55485564
RUN_TEST(kotlin_function);
55495565
RUN_TEST(kotlin_class);
55505566
RUN_TEST(scala_function);

0 commit comments

Comments
 (0)