diff --git a/pkg/lang/treesitter/tags.go b/pkg/lang/treesitter/tags.go index 799d96a..8018b28 100644 --- a/pkg/lang/treesitter/tags.go +++ b/pkg/lang/treesitter/tags.go @@ -85,6 +85,14 @@ var supplementalTagsQueries = map[string]string{ "cpp": strings.Join([]string{ "(namespace_definition name: (namespace_identifier) @name) @definition.module", }, "\n"), + // gotreesitter's inferred C# tag query indexes interfaces, classes, and + // methods but drops `namespace_declaration` containers, the primary + // container for exported C# APIs. Capture both simple (identifier) and + // qualified namespace names as module definitions without disturbing any + // existing captures. + "c_sharp": strings.Join([]string{ + "(namespace_declaration name: [(identifier) (qualified_name)] @name) @definition.module", + }, "\n"), } // ResolveTagsQuery returns the tree-sitter tags query canopy should use for a diff --git a/pkg/lang/treesitter/tags_csharp_test.go b/pkg/lang/treesitter/tags_csharp_test.go new file mode 100644 index 0000000..dca7fdd --- /dev/null +++ b/pkg/lang/treesitter/tags_csharp_test.go @@ -0,0 +1,52 @@ +package treesitter + +import "testing" + +const csharpNamespaceSample = `namespace Acme.Telemetry +{ + public interface IClock + { + void Tick(); + } + + public class Clock : IClock + { + public void Tick() {} + } +} + +namespace Utilities +{ + public class Parser {} +} +` + +func TestCSharpNamespaceDeclarationsIndexedAsModules(t *testing.T) { + entry := findEntryByExtension(t, ".cs") + parser, err := NewParser(entry) + if err != nil { + t.Fatalf("NewParser: %v", err) + } + summary, err := parser.Parse("sample.cs", []byte(csharpNamespaceSample)) + if err != nil { + t.Fatalf("Parse: %v", err) + } + + if !hasSymbol(summary, "interface_definition", "IClock") { + t.Error("missing C# interface IClock") + } + for _, cls := range []string{"Clock", "Parser"} { + if !hasSymbol(summary, "class_definition", cls) { + t.Errorf("missing C# class %s", cls) + } + } + if !hasSymbol(summary, "method_definition", "Tick") { + t.Error("missing C# methods Tick") + } + if !hasSymbol(summary, "module_definition", "Acme.Telemetry") { + t.Error("missing C# namespace Acme.Telemetry") + } + if !hasSymbol(summary, "module_definition", "Utilities") { + t.Error("missing C# namespace Utilities") + } +}