From 31b94360e9de9d63c06f14d9e9fe5a763a68d79d Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 12:56:31 +0900 Subject: [PATCH 01/11] Document symbol kind taxonomy (#1762) --- DEVELOPER_GUIDE.md | 54 +++++++++++++++++ changelog.d/unreleased/1762.docs.md | 16 +++++ src/CodeIndex/Models/SymbolKindCatalog.cs | 71 +++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 changelog.d/unreleased/1762.docs.md create mode 100644 src/CodeIndex/Models/SymbolKindCatalog.cs diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 9c6f21105e..23278ea398 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -129,6 +129,60 @@ Query commands that accept path filters (`search`, `definition`, `references`, ` Do not add mutable static caches, shared `StringBuilder` instances, reused `MatchCollection` enumerators, or singleton scanner state to extractor code. If a future extractor needs cross-call memoization, use an explicit thread-safe collection and add a targeted parallel regression test that proves deterministic output under concurrent calls. +### Symbol Kind Taxonomy + +`symbols.kind`, `symbols.container_kind`, and `symbol_references.container_kind` use the public symbol kind taxonomy below. New extractors must register new kind values in `SymbolKindCatalog` before writing them so schema checks, writer validation, CLI filters, and downstream JSON consumers stay aligned. + +| Kind | Current producers / meaning | Graph behavior | +|---|---|---| +| `attribute` | Razor attributes and metadata-like declarations | Context/search symbol; not a call edge by itself | +| `class` | Class declarations across object-oriented languages | Definition target and container | +| `code` | Markdown fenced or structured code blocks | Search/outline symbol | +| `constant` | Constant declarations where the language distinguishes them | Search/filter symbol | +| `enum` | Enum declarations | Definition target and container | +| `event` | Event declarations | Search/filter symbol | +| `field` | Field declarations where distinct from properties | Search/filter symbol | +| `function` | Functions, methods, constructors, delegates, tasks, and callable bindings that do not have a narrower kind | Primary callable definition; participates in callers/callees through reference rows | +| `heading` | Markdown headings | Outline symbol | +| `hook` | JavaScript/TypeScript React custom hook bindings | Callable-like search/filter symbol | +| `implements` | Razor `@implements` directives | Context/search symbol | +| `import` | Imports, using directives, aliases, and package includes | Search/filter symbol | +| `interface` | Interface declarations | Definition target and container | +| `lambda` | Named lambda/arrow bindings | Callable definition; participates in callers/callees through reference rows | +| `layout` | Razor layout directives | Context/search symbol | +| `method` | Languages or hooks that explicitly distinguish methods from functions | Callable definition; participates in callers/callees through reference rows | +| `module` | Module declarations | Definition target and container | +| `namespace` | Namespace declarations | Definition target and container | +| `operator` | C# operator overload and conversion operator declarations | Callable definition; participates in callers/callees through reference rows | +| `package` | Package declarations | Namespace-like context symbol | +| `property` | Properties and property-like fields | Definition target; not treated as a call edge by itself | +| `reference` | Secondary extracted symbolic references, such as HTML classes or metadata keys | Search/filter symbol | +| `route` | Razor route directives | Context/search symbol | +| `service` | Service declarations in IDL/protobuf-like languages | Definition target and container | +| `struct` | Struct declarations | Definition target and container | +| `test.method` | Test methods detected by test-aware extraction | Callable definition; participates in callers/callees through reference rows | +| `type` | Type declarations where a narrower class/interface/struct/enum kind is not available | Definition target | +| `variable` | Variable bindings | Search/filter symbol | + +`symbol_references.reference_kind` uses this separate reference taxonomy: + +| Reference kind | Meaning | +|---|---| +| `attribute` | Metadata/attribute usage | +| `augmentation` | TypeScript declaration/interface merge edge | +| `call` | Function, method, operator, macro, or command call | +| `const_assertion` | TypeScript `as const` assertion edge | +| `copy_from` | Dockerfile `COPY --from=` stage dependency | +| `extends` | Inheritance or type-extension relationship | +| `from` | Dockerfile `FROM ` dependency | +| `implement` | Interface implementation relationship | +| `import` | Import/include/reference through a module system | +| `instantiate` | Constructor or object creation | +| `metadata` | Metadata-only reference | +| `stage` | Build-stage relationship | +| `type_reference` | Type annotation, generic constraint, or other type-position reference | +| `use` | Generic usage relationship when no narrower reference kind applies | + ### Status freshness age threshold `status --check` keeps the DB/worktree checksum comparison in `IndexFreshnessChecker`, but the user-facing age hint threshold is resolved in `QueryCommandRunner`: CLI `--stale-after ` wins over `CDIDX_STALE_AFTER`, which wins over `.cdidxrc.json`'s `stale_after`, then the 24-hour default. Supported duration suffixes are `m`, `h`, and `d`. JSON output includes `stale_after_seconds` and `index_age_seconds` only for `--check`, so clients can confirm which threshold was applied without inferring it from text. diff --git a/changelog.d/unreleased/1762.docs.md b/changelog.d/unreleased/1762.docs.md new file mode 100644 index 0000000000..47e98ba3c6 --- /dev/null +++ b/changelog.d/unreleased/1762.docs.md @@ -0,0 +1,16 @@ +--- +category: docs +issues: + - 1762 +affected: + - DEVELOPER_GUIDE.md + - src/CodeIndex/Models/SymbolKindCatalog.cs +--- + +## English + +- **Documented the symbol kind taxonomy (#1762)** — `DEVELOPER_GUIDE.md` now lists the public symbol/reference kind values, and `SymbolKindCatalog` centralizes the registered values for code paths that need to enforce the taxonomy. + +## 日本語 + +- **symbol kind taxonomy を文書化しました (#1762)** — `DEVELOPER_GUIDE.md` に公開 symbol/reference kind 値を一覧化し、taxonomy を検証するコードが参照できるよう `SymbolKindCatalog` に登録値を集約しました。 diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs new file mode 100644 index 0000000000..ff45c3b066 --- /dev/null +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -0,0 +1,71 @@ +namespace CodeIndex.Models; + +/// +/// Public taxonomy for persisted symbol and reference kind values. +/// 永続化される symbol/reference kind 値の公開 taxonomy。 +/// +public static class SymbolKindCatalog +{ + public static readonly string[] SymbolKinds = + [ + "attribute", + "class", + "code", + "constant", + "enum", + "event", + "field", + "function", + "heading", + "hook", + "implements", + "import", + "interface", + "lambda", + "layout", + "method", + "module", + "namespace", + "operator", + "package", + "property", + "reference", + "route", + "service", + "struct", + "test.method", + "type", + "variable", + ]; + + public static readonly string[] ReferenceKinds = + [ + "attribute", + "augmentation", + "call", + "const_assertion", + "copy_from", + "extends", + "from", + "implement", + "import", + "instantiate", + "metadata", + "stage", + "type_reference", + "use", + ]; + + public static bool IsValidSymbolKind(string? kind) + => Contains(SymbolKinds, kind); + + public static bool IsValidReferenceKind(string? kind) + => Contains(ReferenceKinds, kind); + + public static string ToSqlCheckInList(IEnumerable values) + => string.Join(", ", values.Select(value => $"'{value.Replace("'", "''", StringComparison.Ordinal)}'")); + + private static bool Contains(IEnumerable values, string? value) + => !string.IsNullOrWhiteSpace(value) + && values.Contains(value, StringComparer.Ordinal); +} From c5332b9feff16aecb7fae6ce7dfac0b1701d1841 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 12:56:45 +0900 Subject: [PATCH 02/11] Validate persisted kind values (#1691) --- changelog.d/unreleased/1691.fixed.md | 17 +++++++++++++++ src/CodeIndex/Database/DbContext.cs | 12 +++++++---- src/CodeIndex/Database/DbWriter.cs | 20 +++++++++++++++++ tests/CodeIndex.Tests/DatabaseTests.cs | 30 ++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 changelog.d/unreleased/1691.fixed.md diff --git a/changelog.d/unreleased/1691.fixed.md b/changelog.d/unreleased/1691.fixed.md new file mode 100644 index 0000000000..d04a09e4a0 --- /dev/null +++ b/changelog.d/unreleased/1691.fixed.md @@ -0,0 +1,17 @@ +--- +category: fixed +issues: + - 1691 +affected: + - src/CodeIndex/Database/DbContext.cs + - src/CodeIndex/Database/DbWriter.cs + - tests/CodeIndex.Tests/DatabaseTests.cs +--- + +## English + +- **Rejected malformed persisted kind values (#1691)** — new schemas add CHECK constraints for symbol/reference kind columns, and writer paths fail fast when extractors try to persist unregistered kind values. + +## 日本語 + +- **不正な kind 値の永続化を拒否するようにしました (#1691)** — 新規 schema が symbol/reference kind 列に CHECK 制約を追加し、extractor が未登録 kind 値を永続化しようとした場合は writer path が早期に失敗します。 diff --git a/src/CodeIndex/Database/DbContext.cs b/src/CodeIndex/Database/DbContext.cs index 9fec4db852..72449202f9 100644 --- a/src/CodeIndex/Database/DbContext.cs +++ b/src/CodeIndex/Database/DbContext.cs @@ -1,5 +1,6 @@ using CodeIndex.Cli; using CodeIndex.Indexer; +using CodeIndex.Models; using Microsoft.Data.Sqlite; using System.Globalization; @@ -1316,12 +1317,15 @@ file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE, UNIQUE(file_id, line, context) )"); + var symbolKindCheck = SymbolKindCatalog.ToSqlCheckInList(SymbolKindCatalog.SymbolKinds); + var referenceKindCheck = SymbolKindCatalog.ToSqlCheckInList(SymbolKindCatalog.ReferenceKinds); + // Symbols table / シンボルテーブル Execute(@" CREATE TABLE IF NOT EXISTS symbols ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE, - kind TEXT, + kind TEXT CHECK (kind IN (" + symbolKindCheck + @")), sub_kind TEXT, name TEXT, line INTEGER, @@ -1331,7 +1335,7 @@ file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE, body_start_line INTEGER, body_end_line INTEGER, signature TEXT, - container_kind TEXT, + container_kind TEXT CHECK (container_kind IS NULL OR container_kind IN (" + symbolKindCheck + @")), container_name TEXT, container_qualified_name TEXT, family_key TEXT, @@ -1346,12 +1350,12 @@ CREATE TABLE IF NOT EXISTS symbol_references ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE, symbol_name TEXT, - reference_kind TEXT, + reference_kind TEXT CHECK (reference_kind IN (" + referenceKindCheck + @")), line INTEGER, column_number INTEGER, context TEXT, reference_line_id INTEGER REFERENCES reference_lines(id), - container_kind TEXT, + container_kind TEXT CHECK (container_kind IS NULL OR container_kind IN (" + symbolKindCheck + @")), container_name TEXT )"); diff --git a/src/CodeIndex/Database/DbWriter.cs b/src/CodeIndex/Database/DbWriter.cs index 2c7e2f85ca..3630f001aa 100644 --- a/src/CodeIndex/Database/DbWriter.cs +++ b/src/CodeIndex/Database/DbWriter.cs @@ -866,6 +866,7 @@ INSERT INTO symbols ( for (int j = start; j < end; j++) { var symbol = symbols[j]; + ValidateSymbolKinds(symbol); var startLine = symbol.StartLine > 0 ? symbol.StartLine : symbol.Line; var endLine = symbol.EndLine > 0 ? symbol.EndLine : startLine; if (j > start) @@ -1026,6 +1027,7 @@ INSERT INTO symbol_references ( for (int j = i; j < end; j++) { var reference = references[j]; + ValidateReferenceKinds(reference); var referenceLineId = referenceLineIds[(reference.FileId, reference.Line, reference.Context)]; if (j > i) @@ -1060,6 +1062,24 @@ INSERT INTO symbol_references ( RefreshMutualRecursionFlags(); } + private static void ValidateSymbolKinds(SymbolRecord symbol) + { + if (!SymbolKindCatalog.IsValidSymbolKind(symbol.Kind)) + throw new ArgumentException($"Unknown symbol kind '{symbol.Kind}'. Register the kind in {nameof(SymbolKindCatalog)} before writing it.", nameof(symbol)); + + if (symbol.ContainerKind != null && !SymbolKindCatalog.IsValidSymbolKind(symbol.ContainerKind)) + throw new ArgumentException($"Unknown symbol container kind '{symbol.ContainerKind}'. Register the kind in {nameof(SymbolKindCatalog)} before writing it.", nameof(symbol)); + } + + private static void ValidateReferenceKinds(ReferenceRecord reference) + { + if (!SymbolKindCatalog.IsValidReferenceKind(reference.ReferenceKind)) + throw new ArgumentException($"Unknown reference kind '{reference.ReferenceKind}'. Register the kind in {nameof(SymbolKindCatalog)} before writing it.", nameof(reference)); + + if (reference.ContainerKind != null && !SymbolKindCatalog.IsValidSymbolKind(reference.ContainerKind)) + throw new ArgumentException($"Unknown reference container kind '{reference.ContainerKind}'. Register the kind in {nameof(SymbolKindCatalog)} before writing it.", nameof(reference)); + } + private Dictionary<(long FileId, int Line, string Context), long> UpsertReferenceLines(IReadOnlyList references, int start, int end) { var contextsByLine = new Dictionary<(long FileId, int Line, string Context), string>(); diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index 21a447b928..9b45644c92 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -98,6 +98,36 @@ public void InsertReferences_UsesFoldedNamesForMutualRecursion() Assert.Equal(2L, (long)cmd.ExecuteScalar()!); } + [Fact] + public void InsertSymbols_UnknownKind_ThrowsBeforePersisting() + { + var ex = Assert.Throws(() => _writer.InsertSymbols( + [ + new SymbolRecord + { + FileId = 1, + Kind = "metohd", + Name = "Run", + Line = 1, + }, + ])); + + Assert.Contains("Unknown symbol kind", ex.Message); + } + + [Fact] + public void InitializeSchema_ConstrainsKindColumns() + { + using var cmd = _db.Connection.CreateCommand(); + cmd.CommandText = """ + INSERT INTO symbols (file_id, kind, name, line) + VALUES (1, 'metohd', 'Run', 1) + """; + + var ex = Assert.Throws(() => cmd.ExecuteNonQuery()); + Assert.Equal(19, ex.SqliteErrorCode); + } + [Fact] public void OptimizeFts_ResetsIncrementalWriteCounterAndStampsTime() { From 45597c56460d2fff3d8be092a5c25253718bf3bf Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 12:57:17 +0900 Subject: [PATCH 03/11] Classify C# operators as operator symbols (#1965) --- changelog.d/unreleased/1965.fixed.md | 16 ++++ .../Indexer/Symbols/SymbolExtractor.cs | 6 +- tests/CodeIndex.Tests/SymbolExtractorTests.cs | 87 ++++++++++++------- 3 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 changelog.d/unreleased/1965.fixed.md diff --git a/changelog.d/unreleased/1965.fixed.md b/changelog.d/unreleased/1965.fixed.md new file mode 100644 index 0000000000..ed8cd76207 --- /dev/null +++ b/changelog.d/unreleased/1965.fixed.md @@ -0,0 +1,16 @@ +--- +category: fixed +issues: + - 1965 +affected: + - src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs + - tests/CodeIndex.Tests/SymbolExtractorTests.cs +--- + +## English + +- **C# operator overloads now use the `operator` symbol kind (#1965)** — arithmetic, comparison, conversion, checked, and static abstract interface operators are no longer indexed as generic `function` symbols. + +## 日本語 + +- **C# operator overload が `operator` symbol kind を使うようになりました (#1965)** — 算術、比較、変換、checked、static abstract interface の各 operator が汎用 `function` symbol として index されなくなりました。 diff --git a/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs b/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs index 3cc561af32..3aa1611596 100644 --- a/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs +++ b/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs @@ -1097,11 +1097,11 @@ private enum JavaScriptTypeScriptFunctionHeaderConsumeResult // これにより C# 11 の `static abstract` / `abstract static` interface 変換演算子 // (generic math: `System.Numerics.INumber` など)と、interface 上の // default implementation / member hiding 形態を黙って取りこぼさない。Closes #244. - new("function", new Regex( + new("operator", new Regex( $@"^\s*" + $@"(?=(?:(?:{CSharpVisibilityPattern}|static|abstract|virtual|sealed|override|new|unsafe|extern)\s+)*static\s+)" + $@"(?:(?{CSharpVisibilityPattern})\s+|(?:static|abstract|virtual|sealed|override|new|unsafe|extern)\s+)+" - + $@"(?implicit|explicit)\s+operator\b", + + @"(?(?:implicit|explicit)\s+operator\s+.+?)\s*\(", RegexOptions.Compiled), BodyStyle.Brace, "visibility"), // Operator overload (+ - * / == != < > etc.) — must come before method pattern. // Visibility may appear before or after `static`. Closes #355. @@ -1115,7 +1115,7 @@ private enum JavaScriptTypeScriptFunctionHeaderConsumeResult // これにより C# 11 の `static abstract` / `abstract static` interface 演算子 // (generic math: `IAdditionOperators`、`IComparisonOperators` など)を // 黙って取りこぼさない。Closes #244. - new("function", new Regex( + new("operator", new Regex( $@"^\s*" + $@"(?=(?:(?:{CSharpVisibilityPattern}|static|abstract|virtual|sealed|override|new|unsafe|extern)\s+)*static\s+)" + $@"(?:(?{CSharpVisibilityPattern})\s+|(?:static|abstract|virtual|sealed|override|new|unsafe|extern)\s+)+" diff --git a/tests/CodeIndex.Tests/SymbolExtractorTests.cs b/tests/CodeIndex.Tests/SymbolExtractorTests.cs index af6fec0526..b4107e5a3f 100644 --- a/tests/CodeIndex.Tests/SymbolExtractorTests.cs +++ b/tests/CodeIndex.Tests/SymbolExtractorTests.cs @@ -63,6 +63,36 @@ internal static string[] MaskLines(string? lang, string[] originalLines) Assert.Contains(symbols, symbol => symbol.Kind == "class" && symbol.Name == "StructuralLineMasker"); } + [Fact] + public void Extract_CsharpOperatorOverloads_UseOperatorKind() + { + const string content = """ + public readonly struct Point + { + public static Point operator +(Point left, Point right) => left; + public static bool operator ==(Point left, Point right) => true; + public static bool operator !=(Point left, Point right) => false; + public static explicit operator int(Point point) => 0; + public static Point operator checked +(Point left, Point right) => left; + } + + public interface IAddable + { + static abstract TSelf operator +(TSelf left, TSelf right); + } + """; + + var symbols = SymbolExtractor.Extract(1, "csharp", content); + + Assert.Contains(symbols, symbol => symbol.Kind == "operator" && symbol.Name == "operator +"); + Assert.Contains(symbols, symbol => symbol.Kind == "operator" && symbol.Name == "operator =="); + Assert.Contains(symbols, symbol => symbol.Kind == "operator" && symbol.Name == "operator !="); + Assert.Contains(symbols, symbol => symbol.Kind == "operator" && symbol.Name == "explicit operator int"); + Assert.Contains(symbols, symbol => symbol.Kind == "operator" && symbol.Name == "operator checked +"); + Assert.Contains(symbols, symbol => symbol.Kind == "operator" && symbol.ContainerKind == "interface"); + Assert.DoesNotContain(symbols, symbol => symbol.Kind == "function" && symbol.Name.StartsWith("operator", StringComparison.Ordinal)); + } + [Fact] public void Extract_PythonDataclassField_IndexesFieldAndMetadataKeys() { @@ -7272,9 +7302,9 @@ public class Source """; var symbols = SymbolExtractor.Extract(1, "csharp", content); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "implicit operator class"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator Outer.class.Target"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator List"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "implicit operator class"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator Outer.class.Target"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator List"); Assert.DoesNotContain(symbols, s => s.Kind == "function" && s.Name.Contains("@", StringComparison.Ordinal)); } @@ -11237,20 +11267,17 @@ public void Extract_CSharp_DetectsOperatorOverloads() var symbols = SymbolExtractor.Extract(1, "csharp", content); Assert.Contains(symbols, s => s.Kind == "struct" && s.Name == "Money"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator +"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator -"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator =="); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator checked +"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "implicit operator decimal"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator Money"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator checked byte"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator Dictionary"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator (int whole, int cents)"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator (Dictionary map, int count)?"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator (int[] items, int count)"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator ((int a, int b) pair, int count)"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator int*"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator delegate* unmanaged[Cdecl]"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator +"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator -"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator =="); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator checked +"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "implicit operator decimal"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator Money"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator checked byte"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator Dictionary"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator (int whole,int cents)"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator (int[] items, int count)"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator int*"); } [Fact] @@ -11281,12 +11308,12 @@ public struct N """; var symbols = SymbolExtractor.Extract(1, "csharp", content); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator +"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator checked +"); - Assert.Equal(2, symbols.Count(s => s.Kind == "function" && s.Name == "operator -")); - Assert.Equal(2, symbols.Count(s => s.Kind == "function" && s.Name == "operator checked -")); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator int"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator checked int"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator +"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator checked +"); + Assert.Equal(2, symbols.Count(s => s.Kind == "operator" && s.Name == "operator -")); + Assert.Equal(2, symbols.Count(s => s.Kind == "operator" && s.Name == "operator checked -")); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator int"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator checked int"); } [Fact] @@ -11328,11 +11355,11 @@ public struct N var symbols = SymbolExtractor.Extract(1, "csharp", content); Assert.Contains(symbols, s => s.Kind == "interface" && s.Name == "IMath"); - Assert.Equal(2, symbols.Count(s => s.Kind == "function" && s.Name == "operator +")); - Assert.Equal(2, symbols.Count(s => s.Kind == "function" && s.Name == "operator -")); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator *"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "implicit operator T"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator int"); + Assert.Equal(2, symbols.Count(s => s.Kind == "operator" && s.Name == "operator +")); + Assert.Equal(2, symbols.Count(s => s.Kind == "operator" && s.Name == "operator -")); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator *"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "implicit operator T"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator int"); Assert.Contains(symbols, s => s.Kind == "property" && s.Name == "Zero"); Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "Compare"); // Widening the modifier slot also incidentally covers C# 11 user-defined checked @@ -11345,8 +11372,8 @@ public struct N // operator 名キャプチャが `checked` を含む形を受け入れているため、 // ここでは二項 `operator checked +` と変換 `explicit operator checked int` の // 両方を固定し、将来 modifier スロットが狭められても無言で落ちないようにする。 - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "operator checked +"); - Assert.Contains(symbols, s => s.Kind == "function" && s.Name == "explicit operator checked int"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "operator checked +"); + Assert.Contains(symbols, s => s.Kind == "operator" && s.Name == "explicit operator checked int"); } [Fact] From df8864ad43af126ec395f295bbb7b48883a529b5 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:06:04 +0900 Subject: [PATCH 04/11] Align reference kind validation with existing taxonomy (#1691) --- DEVELOPER_GUIDE.md | 8 +++++ src/CodeIndex/Models/SymbolKindCatalog.cs | 8 +++++ tests/CodeIndex.Tests/DatabaseTests.cs | 37 +++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 23278ea398..3d55a882c0 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -168,19 +168,27 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | Reference kind | Meaning | |---|---| +| `annotation` | Annotation usage in languages that distinguish annotations from attributes | | `attribute` | Metadata/attribute usage | | `augmentation` | TypeScript declaration/interface merge edge | | `call` | Function, method, operator, macro, or command call | +| `capture` | Captured callback/delegate relationship used by impact analysis | +| `consumes_hook` | React hook consumption relationship | | `const_assertion` | TypeScript `as const` assertion edge | | `copy_from` | Dockerfile `COPY --from=` stage dependency | | `extends` | Inheritance or type-extension relationship | | `from` | Dockerfile `FROM ` dependency | +| `friend` | C++ friend declaration relationship | | `implement` | Interface implementation relationship | +| `implicit_implementation` | C# implicit interface implementation relationship | | `import` | Import/include/reference through a module system | | `instantiate` | Constructor or object creation | | `metadata` | Metadata-only reference | +| `razor_event_binding` | Razor event binding relationship | | `stage` | Build-stage relationship | +| `subscribe` | Event subscription relationship | | `type_reference` | Type annotation, generic constraint, or other type-position reference | +| `unsubscribe` | Event unsubscription relationship | | `use` | Generic usage relationship when no narrower reference kind applies | ### Status freshness age threshold diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index ff45c3b066..66bd9b2da3 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -40,19 +40,27 @@ public static class SymbolKindCatalog public static readonly string[] ReferenceKinds = [ + "annotation", "attribute", "augmentation", "call", + "capture", + "consumes_hook", "const_assertion", "copy_from", "extends", "from", + "friend", "implement", + "implicit_implementation", "import", "instantiate", "metadata", "stage", + "razor_event_binding", + "subscribe", "type_reference", + "unsubscribe", "use", ]; diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index 9b45644c92..b64854f288 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -115,6 +115,43 @@ public void InsertSymbols_UnknownKind_ThrowsBeforePersisting() Assert.Contains("Unknown symbol kind", ex.Message); } + [Theory] + [InlineData("annotation")] + [InlineData("subscribe")] + [InlineData("implicit_implementation")] + public void InsertReferences_ExistingReferenceKinds_AreAccepted(string referenceKind) + { + var fileId = _writer.UpsertFile(new FileRecord + { + Path = $"src/{referenceKind}.cs", + Lang = "csharp", + Size = 32, + Lines = 1, + Modified = new DateTime(2026, 5, 25, 0, 0, 0, DateTimeKind.Utc), + Checksum = referenceKind, + }); + + _writer.InsertReferences( + [ + new ReferenceRecord + { + FileId = fileId, + SymbolName = "Target", + ReferenceKind = referenceKind, + Line = 1, + Column = 1, + Context = "Target();", + ContainerKind = "function", + ContainerName = "Caller", + }, + ]); + + using var cmd = _db.Connection.CreateCommand(); + cmd.CommandText = "SELECT COUNT(*) FROM symbol_references WHERE reference_kind = @kind"; + cmd.Parameters.AddWithValue("@kind", referenceKind); + Assert.Equal(1L, (long)cmd.ExecuteScalar()!); + } + [Fact] public void InitializeSchema_ConstrainsKindColumns() { From 8b06744fbc9decb6d66b84a5b449df19b5424d33 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:11:01 +0900 Subject: [PATCH 05/11] Address kind validation review findings (#1691 #1965) --- DEVELOPER_GUIDE.md | 1 + .../Database/DbReader.CSharpResolution.cs | 2 +- src/CodeIndex/Database/DbWriter.cs | 2 +- .../Languages/CSharpReferenceExtractor.cs | 2 +- src/CodeIndex/Models/SymbolKindCatalog.cs | 1 + tests/CodeIndex.Tests/DatabaseTests.cs | 29 +++++++++++++++++++ 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 3d55a882c0..49cb6b717a 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -139,6 +139,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `class` | Class declarations across object-oriented languages | Definition target and container | | `code` | Markdown fenced or structured code blocks | Search/outline symbol | | `constant` | Constant declarations where the language distinguishes them | Search/filter symbol | +| `delegate` | C# / F# delegate declarations | Callable type definition and container-like target | | `enum` | Enum declarations | Definition target and container | | `event` | Event declarations | Search/filter symbol | | `field` | Field declarations where distinct from properties | Search/filter symbol | diff --git a/src/CodeIndex/Database/DbReader.CSharpResolution.cs b/src/CodeIndex/Database/DbReader.CSharpResolution.cs index 8156c9de2d..a601bd2b88 100644 --- a/src/CodeIndex/Database/DbReader.CSharpResolution.cs +++ b/src/CodeIndex/Database/DbReader.CSharpResolution.cs @@ -191,7 +191,7 @@ SELECT s.container_qualified_name FROM symbols s JOIN files f ON s.file_id = f.id WHERE f.lang = 'csharp' - AND s.kind IN ('function', 'property') + AND s.kind IN ('function', 'operator', 'property') AND s.container_qualified_name IS NOT NULL AND s.container_qualified_name != '' AND s.name = @memberName COLLATE NOCASE diff --git a/src/CodeIndex/Database/DbWriter.cs b/src/CodeIndex/Database/DbWriter.cs index 3630f001aa..6dcbe00e33 100644 --- a/src/CodeIndex/Database/DbWriter.cs +++ b/src/CodeIndex/Database/DbWriter.cs @@ -930,7 +930,7 @@ FROM symbols s s.kind = 'interface' OR ( s.container_kind = 'interface' - AND s.kind IN ('function', 'property') + AND s.kind IN ('function', 'operator', 'property') AND s.signature LIKE '%static%' AND (s.signature LIKE '%abstract%' OR s.signature LIKE '%virtual%') ) diff --git a/src/CodeIndex/Indexer/References/Languages/CSharpReferenceExtractor.cs b/src/CodeIndex/Indexer/References/Languages/CSharpReferenceExtractor.cs index 27b66b921e..df3afc0763 100644 --- a/src/CodeIndex/Indexer/References/Languages/CSharpReferenceExtractor.cs +++ b/src/CodeIndex/Indexer/References/Languages/CSharpReferenceExtractor.cs @@ -495,7 +495,7 @@ public static void EmitQualifiedEnumMemberReferences( { foreach (var candidate in candidates) { - if (candidate.Kind != "function") + if (candidate.Kind is not ("function" or "operator")) continue; if (candidate.StartLine <= lineNumber && candidate.BodyEndLine!.Value >= lineNumber) return candidate; diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index 66bd9b2da3..0c72dc1c14 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -12,6 +12,7 @@ public static class SymbolKindCatalog "class", "code", "constant", + "delegate", "enum", "event", "field", diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index b64854f288..ecbe95c449 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -152,6 +152,35 @@ public void InsertReferences_ExistingReferenceKinds_AreAccepted(string reference Assert.Equal(1L, (long)cmd.ExecuteScalar()!); } + [Fact] + public void InsertSymbols_ExistingDelegateKind_IsAccepted() + { + var fileId = _writer.UpsertFile(new FileRecord + { + Path = "src/delegate.cs", + Lang = "csharp", + Size = 32, + Lines = 1, + Modified = new DateTime(2026, 5, 25, 0, 0, 0, DateTimeKind.Utc), + Checksum = "delegate", + }); + + _writer.InsertSymbols( + [ + new SymbolRecord + { + FileId = fileId, + Kind = "delegate", + Name = "Handler", + Line = 1, + }, + ]); + + using var cmd = _db.Connection.CreateCommand(); + cmd.CommandText = "SELECT COUNT(*) FROM symbols WHERE kind = 'delegate'"; + Assert.Equal(1L, (long)cmd.ExecuteScalar()!); + } + [Fact] public void InitializeSchema_ConstrainsKindColumns() { From 689c394efbb6ab6db2e6beaa511b72e49db1ce47 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:21:12 +0900 Subject: [PATCH 06/11] Complete operator contract detection (#1691 #1965) --- DEVELOPER_GUIDE.md | 1 + src/CodeIndex/Cli/IndexCommandRunner.cs | 2 +- src/CodeIndex/Database/DbWriter.cs | 2 +- src/CodeIndex/Mcp/McpToolHandlers.cs | 2 +- src/CodeIndex/Models/SymbolKindCatalog.cs | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 49cb6b717a..a94eaa0b0e 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -185,6 +185,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `import` | Import/include/reference through a module system | | `instantiate` | Constructor or object creation | | `metadata` | Metadata-only reference | +| `reference` | Generic persisted reference row used by fixtures or extractors without a narrower edge kind | | `razor_event_binding` | Razor event binding relationship | | `stage` | Build-stage relationship | | `subscribe` | Event subscription relationship | diff --git a/src/CodeIndex/Cli/IndexCommandRunner.cs b/src/CodeIndex/Cli/IndexCommandRunner.cs index daf07cfff1..406eedabd5 100644 --- a/src/CodeIndex/Cli/IndexCommandRunner.cs +++ b/src/CodeIndex/Cli/IndexCommandRunner.cs @@ -4636,7 +4636,7 @@ private static int CountConsecutiveQuotes(char[] chars, int index) } private static bool IsCSharpStaticInterfaceContractSymbol(SymbolRecord symbol) - => symbol.Kind is "function" or "property" + => symbol.Kind is "function" or "operator" or "property" && symbol.ContainerKind == "interface" && !string.IsNullOrWhiteSpace(symbol.Signature) && ContainsCSharpWord(symbol.Signature!, "static") diff --git a/src/CodeIndex/Database/DbWriter.cs b/src/CodeIndex/Database/DbWriter.cs index 6dcbe00e33..7dcdaa150e 100644 --- a/src/CodeIndex/Database/DbWriter.cs +++ b/src/CodeIndex/Database/DbWriter.cs @@ -980,7 +980,7 @@ FROM symbols s JOIN files f ON f.id = s.file_id WHERE f.lang = 'csharp' AND s.container_kind = 'interface' - AND s.kind IN ('function', 'property') + AND s.kind IN ('function', 'operator', 'property') AND s.signature LIKE '%static%' AND (s.signature LIKE '%abstract%' OR s.signature LIKE '%virtual%')"; diff --git a/src/CodeIndex/Mcp/McpToolHandlers.cs b/src/CodeIndex/Mcp/McpToolHandlers.cs index dbca703f0f..8e8a11fee7 100644 --- a/src/CodeIndex/Mcp/McpToolHandlers.cs +++ b/src/CodeIndex/Mcp/McpToolHandlers.cs @@ -3169,7 +3169,7 @@ private static CSharpStaticInterfaceWorkspaceSymbols BuildMcpCSharpStaticInterfa } private static bool IsMcpCSharpStaticInterfaceContractSymbol(SymbolRecord symbol) - => symbol.Kind is "function" or "property" + => symbol.Kind is "function" or "operator" or "property" && symbol.ContainerKind == "interface" && !string.IsNullOrWhiteSpace(symbol.Signature) && ContainsMcpCSharpWord(symbol.Signature!, "static") diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index 0c72dc1c14..55668043b9 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -57,6 +57,7 @@ public static class SymbolKindCatalog "import", "instantiate", "metadata", + "reference", "stage", "razor_event_binding", "subscribe", From 5065f98c99b38348d08dd6032b94a8bd92745247 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:27:12 +0900 Subject: [PATCH 07/11] Complete symbol kind taxonomy coverage (#1691) --- DEVELOPER_GUIDE.md | 7 +++++++ src/CodeIndex/Models/SymbolKindCatalog.cs | 7 +++++++ tests/CodeIndex.Tests/DatabaseTests.cs | 21 +++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index a94eaa0b0e..4cb2e88cca 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -136,6 +136,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | Kind | Current producers / meaning | Graph behavior | |---|---|---| | `attribute` | Razor attributes and metadata-like declarations | Context/search symbol; not a call edge by itself | +| `associatedtype` | Swift associated type declarations | Type-like definition target | | `class` | Class declarations across object-oriented languages | Definition target and container | | `code` | Markdown fenced or structured code blocks | Search/outline symbol | | `constant` | Constant declarations where the language distinguishes them | Search/filter symbol | @@ -143,6 +144,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `enum` | Enum declarations | Definition target and container | | `event` | Event declarations | Search/filter symbol | | `field` | Field declarations where distinct from properties | Search/filter symbol | +| `file_module` | File-scoped module/package declarations | Namespace-like context symbol | | `function` | Functions, methods, constructors, delegates, tasks, and callable bindings that do not have a narrower kind | Primary callable definition; participates in callers/callees through reference rows | | `heading` | Markdown headings | Outline symbol | | `hook` | JavaScript/TypeScript React custom hook bindings | Callable-like search/filter symbol | @@ -157,12 +159,17 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `operator` | C# operator overload and conversion operator declarations | Callable definition; participates in callers/callees through reference rows | | `package` | Package declarations | Namespace-like context symbol | | `property` | Properties and property-like fields | Definition target; not treated as a call edge by itself | +| `protocol` | Protocol declarations in languages that distinguish protocols from interfaces | Definition target and container | | `reference` | Secondary extracted symbolic references, such as HTML classes or metadata keys | Search/filter symbol | | `route` | Razor route directives | Context/search symbol | | `service` | Service declarations in IDL/protobuf-like languages | Definition target and container | +| `specialization` | C++ template specialization declarations | Definition target for specialized type/function forms | | `struct` | Struct declarations | Definition target and container | | `test.method` | Test methods detected by test-aware extraction | Callable definition; participates in callers/callees through reference rows | +| `trait` | Trait declarations in languages that distinguish traits from interfaces | Definition target and container | | `type` | Type declarations where a narrower class/interface/struct/enum kind is not available | Definition target | +| `typealias` | Type alias declarations | Definition target for alias names | +| `union` | Union declarations | Definition target and container | | `variable` | Variable bindings | Search/filter symbol | `symbol_references.reference_kind` uses this separate reference taxonomy: diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index 55668043b9..87cec2bc22 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -9,6 +9,7 @@ public static class SymbolKindCatalog public static readonly string[] SymbolKinds = [ "attribute", + "associatedtype", "class", "code", "constant", @@ -16,6 +17,7 @@ public static class SymbolKindCatalog "enum", "event", "field", + "file_module", "function", "heading", "hook", @@ -30,12 +32,17 @@ public static class SymbolKindCatalog "operator", "package", "property", + "protocol", "reference", "route", "service", + "specialization", "struct", "test.method", + "trait", "type", + "typealias", + "union", "variable", ]; diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index ecbe95c449..5baa351494 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -152,17 +152,25 @@ public void InsertReferences_ExistingReferenceKinds_AreAccepted(string reference Assert.Equal(1L, (long)cmd.ExecuteScalar()!); } - [Fact] - public void InsertSymbols_ExistingDelegateKind_IsAccepted() + [Theory] + [InlineData("delegate")] + [InlineData("union")] + [InlineData("specialization")] + [InlineData("protocol")] + [InlineData("file_module")] + [InlineData("trait")] + [InlineData("associatedtype")] + [InlineData("typealias")] + public void InsertSymbols_ExistingExtractorKinds_AreAccepted(string symbolKind) { var fileId = _writer.UpsertFile(new FileRecord { - Path = "src/delegate.cs", + Path = $"src/{symbolKind}.txt", Lang = "csharp", Size = 32, Lines = 1, Modified = new DateTime(2026, 5, 25, 0, 0, 0, DateTimeKind.Utc), - Checksum = "delegate", + Checksum = symbolKind, }); _writer.InsertSymbols( @@ -170,14 +178,15 @@ public void InsertSymbols_ExistingDelegateKind_IsAccepted() new SymbolRecord { FileId = fileId, - Kind = "delegate", + Kind = symbolKind, Name = "Handler", Line = 1, }, ]); using var cmd = _db.Connection.CreateCommand(); - cmd.CommandText = "SELECT COUNT(*) FROM symbols WHERE kind = 'delegate'"; + cmd.CommandText = "SELECT COUNT(*) FROM symbols WHERE kind = @kind"; + cmd.Parameters.AddWithValue("@kind", symbolKind); Assert.Equal(1L, (long)cmd.ExecuteScalar()!); } From 3d76d607ff5ccae740d0a6c49357704feedc0391 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:29:35 +0900 Subject: [PATCH 08/11] Cover JavaScript callable kind taxonomy (#1691) --- DEVELOPER_GUIDE.md | 3 +++ src/CodeIndex/Models/SymbolKindCatalog.cs | 3 +++ tests/CodeIndex.Tests/DatabaseTests.cs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 4cb2e88cca..039c2e59f5 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -135,6 +135,8 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | Kind | Current producers / meaning | Graph behavior | |---|---|---| +| `async_function` | JavaScript/TypeScript async function declarations | Callable definition; participates in callers/callees through reference rows | +| `async_generator` | JavaScript/TypeScript async generator declarations | Callable definition; participates in callers/callees through reference rows | | `attribute` | Razor attributes and metadata-like declarations | Context/search symbol; not a call edge by itself | | `associatedtype` | Swift associated type declarations | Type-like definition target | | `class` | Class declarations across object-oriented languages | Definition target and container | @@ -146,6 +148,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `field` | Field declarations where distinct from properties | Search/filter symbol | | `file_module` | File-scoped module/package declarations | Namespace-like context symbol | | `function` | Functions, methods, constructors, delegates, tasks, and callable bindings that do not have a narrower kind | Primary callable definition; participates in callers/callees through reference rows | +| `generator` | JavaScript/TypeScript generator declarations | Callable definition; participates in callers/callees through reference rows | | `heading` | Markdown headings | Outline symbol | | `hook` | JavaScript/TypeScript React custom hook bindings | Callable-like search/filter symbol | | `implements` | Razor `@implements` directives | Context/search symbol | diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index 87cec2bc22..a32d52424e 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -8,6 +8,8 @@ public static class SymbolKindCatalog { public static readonly string[] SymbolKinds = [ + "async_function", + "async_generator", "attribute", "associatedtype", "class", @@ -19,6 +21,7 @@ public static class SymbolKindCatalog "field", "file_module", "function", + "generator", "heading", "hook", "implements", diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index 5baa351494..22efabe9bc 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -153,7 +153,10 @@ public void InsertReferences_ExistingReferenceKinds_AreAccepted(string reference } [Theory] + [InlineData("async_function")] + [InlineData("async_generator")] [InlineData("delegate")] + [InlineData("generator")] [InlineData("union")] [InlineData("specialization")] [InlineData("protocol")] From 63d1fdca3d7db36782334d4840209147ca9369fa Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:32:31 +0900 Subject: [PATCH 09/11] Cover remaining extractor kind taxonomy (#1691) --- DEVELOPER_GUIDE.md | 10 ++++++++++ src/CodeIndex/Models/SymbolKindCatalog.cs | 10 ++++++++++ tests/CodeIndex.Tests/DatabaseTests.cs | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 039c2e59f5..dbfd5345e9 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -135,11 +135,14 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | Kind | Current producers / meaning | Graph behavior | |---|---|---| +| `accessor` | Accessor declarations when extracted separately from their owning property | Search/filter symbol | +| `annotation` | Annotation declarations or annotation-like language constructs | Metadata/search symbol | | `async_function` | JavaScript/TypeScript async function declarations | Callable definition; participates in callers/callees through reference rows | | `async_generator` | JavaScript/TypeScript async generator declarations | Callable definition; participates in callers/callees through reference rows | | `attribute` | Razor attributes and metadata-like declarations | Context/search symbol; not a call edge by itself | | `associatedtype` | Swift associated type declarations | Type-like definition target | | `class` | Class declarations across object-oriented languages | Definition target and container | +| `class_hook` | Python class hook methods such as dunder hooks reclassified from functions | Callable/search symbol | | `code` | Markdown fenced or structured code blocks | Search/outline symbol | | `constant` | Constant declarations where the language distinguishes them | Search/filter symbol | | `delegate` | C# / F# delegate declarations | Callable type definition and container-like target | @@ -160,19 +163,25 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `module` | Module declarations | Definition target and container | | `namespace` | Namespace declarations | Definition target and container | | `operator` | C# operator overload and conversion operator declarations | Callable definition; participates in callers/callees through reference rows | +| `object` | Object-literal/object container context used by nested extracted symbols | Container context | | `package` | Package declarations | Namespace-like context symbol | | `property` | Properties and property-like fields | Definition target; not treated as a call edge by itself | +| `procedure` | Procedure declarations in languages such as Fortran | Callable definition | +| `program` | Program block declarations in languages such as Fortran | Definition target and container | | `protocol` | Protocol declarations in languages that distinguish protocols from interfaces | Definition target and container | | `reference` | Secondary extracted symbolic references, such as HTML classes or metadata keys | Search/filter symbol | | `route` | Razor route directives | Context/search symbol | | `service` | Service declarations in IDL/protobuf-like languages | Definition target and container | | `specialization` | C++ template specialization declarations | Definition target for specialized type/function forms | | `struct` | Struct declarations | Definition target and container | +| `submodule` | Fortran submodule declarations | Namespace/module-like definition target | +| `subroutine` | Fortran subroutine declarations | Callable definition | | `test.method` | Test methods detected by test-aware extraction | Callable definition; participates in callers/callees through reference rows | | `trait` | Trait declarations in languages that distinguish traits from interfaces | Definition target and container | | `type` | Type declarations where a narrower class/interface/struct/enum kind is not available | Definition target | | `typealias` | Type alias declarations | Definition target for alias names | | `union` | Union declarations | Definition target and container | +| `block data` | Fortran block data declarations | Definition target | | `variable` | Variable bindings | Search/filter symbol | `symbol_references.reference_kind` uses this separate reference taxonomy: @@ -190,6 +199,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `extends` | Inheritance or type-extension relationship | | `from` | Dockerfile `FROM ` dependency | | `friend` | C++ friend declaration relationship | +| `generic_type_argument` | Generic type argument attached to an explicit invocation | | `implement` | Interface implementation relationship | | `implicit_implementation` | C# implicit interface implementation relationship | | `import` | Import/include/reference through a module system | diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index a32d52424e..a7e1e20099 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -8,11 +8,14 @@ public static class SymbolKindCatalog { public static readonly string[] SymbolKinds = [ + "accessor", + "annotation", "async_function", "async_generator", "attribute", "associatedtype", "class", + "class_hook", "code", "constant", "delegate", @@ -33,19 +36,25 @@ public static class SymbolKindCatalog "module", "namespace", "operator", + "object", "package", "property", + "procedure", + "program", "protocol", "reference", "route", "service", "specialization", "struct", + "submodule", + "subroutine", "test.method", "trait", "type", "typealias", "union", + "block data", "variable", ]; @@ -62,6 +71,7 @@ public static class SymbolKindCatalog "extends", "from", "friend", + "generic_type_argument", "implement", "implicit_implementation", "import", diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index 22efabe9bc..40633a1e9a 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -117,6 +117,7 @@ public void InsertSymbols_UnknownKind_ThrowsBeforePersisting() [Theory] [InlineData("annotation")] + [InlineData("generic_type_argument")] [InlineData("subscribe")] [InlineData("implicit_implementation")] public void InsertReferences_ExistingReferenceKinds_AreAccepted(string referenceKind) @@ -153,14 +154,23 @@ public void InsertReferences_ExistingReferenceKinds_AreAccepted(string reference } [Theory] + [InlineData("accessor")] + [InlineData("annotation")] [InlineData("async_function")] [InlineData("async_generator")] + [InlineData("block data")] + [InlineData("class_hook")] [InlineData("delegate")] [InlineData("generator")] + [InlineData("object")] + [InlineData("procedure")] + [InlineData("program")] [InlineData("union")] [InlineData("specialization")] [InlineData("protocol")] [InlineData("file_module")] + [InlineData("submodule")] + [InlineData("subroutine")] [InlineData("trait")] [InlineData("associatedtype")] [InlineData("typealias")] From e54d9c4291153ca4d777410f2149215e1a2e94b9 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:37:10 +0900 Subject: [PATCH 10/11] Treat operators as callable symbols (#1965) --- src/CodeIndex/Database/DbSymbolReader.cs | 2 +- .../Indexer/References/ReferenceExtractor.TypeReferences.cs | 2 +- src/CodeIndex/Indexer/References/ReferenceExtractor.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CodeIndex/Database/DbSymbolReader.cs b/src/CodeIndex/Database/DbSymbolReader.cs index 4cae8157ad..120c606f19 100644 --- a/src/CodeIndex/Database/DbSymbolReader.cs +++ b/src/CodeIndex/Database/DbSymbolReader.cs @@ -1485,7 +1485,7 @@ private static string BuildOutlineSymbolPath(string? containerQualifiedName, str private static bool IsCallableOutlineSymbol(string kind) { - return kind is "function" or "method" or "constructor"; + return kind is "function" or "operator" or "method" or "constructor"; } private static string? TryBuildCompactCallableSignature(string name, string? signature, string? lang) diff --git a/src/CodeIndex/Indexer/References/ReferenceExtractor.TypeReferences.cs b/src/CodeIndex/Indexer/References/ReferenceExtractor.TypeReferences.cs index 58e1ddfbb8..57c8bf27d9 100644 --- a/src/CodeIndex/Indexer/References/ReferenceExtractor.TypeReferences.cs +++ b/src/CodeIndex/Indexer/References/ReferenceExtractor.TypeReferences.cs @@ -115,7 +115,7 @@ private static void EmitCSharpStaticInterfaceMemberImplementationReferences( var interfaceGenericParameters = BuildCSharpInterfaceGenericParameterLookup(workspaceSymbols); var staticMembersByContainer = symbols - .Where(symbol => symbol.Kind is "function" or "property" + .Where(symbol => symbol.Kind is "function" or "operator" or "property" && !string.IsNullOrWhiteSpace(symbol.ContainerName) && !string.IsNullOrWhiteSpace(symbol.Signature) && ContainsCSharpWord(symbol.Signature!, "static")) diff --git a/src/CodeIndex/Indexer/References/ReferenceExtractor.cs b/src/CodeIndex/Indexer/References/ReferenceExtractor.cs index 9a7095a5ed..317fbb818e 100644 --- a/src/CodeIndex/Indexer/References/ReferenceExtractor.cs +++ b/src/CodeIndex/Indexer/References/ReferenceExtractor.cs @@ -102,7 +102,7 @@ internal sealed class CSharpWhereConstraintState }; private static bool IsFunctionLikeSymbolKind(string kind) - => kind is "function" or "lambda" or "async_function" or "generator" or "async_generator"; + => kind is "function" or "operator" or "lambda" or "async_function" or "generator" or "async_generator"; private static readonly Dictionary> LanguageSpecificIgnoredCallNames = new(StringComparer.Ordinal) { From 36e988b81814f7fc7e42d7f1969a23656474f6be Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 25 May 2026 13:53:26 +0900 Subject: [PATCH 11/11] Complete reference taxonomy coverage (#1691 #1965) --- DEVELOPER_GUIDE.md | 7 +++ src/CodeIndex/Models/SymbolKindCatalog.cs | 7 +++ tests/CodeIndex.Tests/DatabaseTests.cs | 7 +++ tests/CodeIndex.Tests/DbReaderTests.cs | 20 ++++---- .../QueryCommandRunnerTests.cs | 50 ++++++------------- 5 files changed, 44 insertions(+), 47 deletions(-) diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index dbfd5345e9..0d1b97daaa 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -170,6 +170,7 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `program` | Program block declarations in languages such as Fortran | Definition target and container | | `protocol` | Protocol declarations in languages that distinguish protocols from interfaces | Definition target and container | | `reference` | Secondary extracted symbolic references, such as HTML classes or metadata keys | Search/filter symbol | +| `rule` | CSS/SCSS rule container context used by nested references | Container context | | `route` | Razor route directives | Context/search symbol | | `service` | Service declarations in IDL/protobuf-like languages | Definition target and container | | `specialization` | C++ template specialization declarations | Definition target for specialized type/function forms | @@ -193,9 +194,13 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `augmentation` | TypeScript declaration/interface merge edge | | `call` | Function, method, operator, macro, or command call | | `capture` | Captured callback/delegate relationship used by impact analysis | +| `column_reference` | SQL column reference in a statement-specific context | | `consumes_hook` | React hook consumption relationship | | `const_assertion` | TypeScript `as const` assertion edge | +| `const_generic_reference` | Rust const generic argument reference | | `copy_from` | Dockerfile `COPY --from=` stage dependency | +| `cte_body_reference` | SQL common table expression body reference | +| `decorator` | Python decorator usage | | `extends` | Inheritance or type-extension relationship | | `from` | Dockerfile `FROM ` dependency | | `friend` | C++ friend declaration relationship | @@ -204,6 +209,8 @@ Do not add mutable static caches, shared `StringBuilder` instances, reused `Matc | `implicit_implementation` | C# implicit interface implementation relationship | | `import` | Import/include/reference through a module system | | `instantiate` | Constructor or object creation | +| `join_condition_reference` | SQL join/merge condition column reference | +| `lifetime_reference` | Rust/C#-style lifetime or lifetime-like type reference | | `metadata` | Metadata-only reference | | `reference` | Generic persisted reference row used by fixtures or extractors without a narrower edge kind | | `razor_event_binding` | Razor event binding relationship | diff --git a/src/CodeIndex/Models/SymbolKindCatalog.cs b/src/CodeIndex/Models/SymbolKindCatalog.cs index a7e1e20099..c2afb6f78e 100644 --- a/src/CodeIndex/Models/SymbolKindCatalog.cs +++ b/src/CodeIndex/Models/SymbolKindCatalog.cs @@ -43,6 +43,7 @@ public static class SymbolKindCatalog "program", "protocol", "reference", + "rule", "route", "service", "specialization", @@ -65,9 +66,13 @@ public static class SymbolKindCatalog "augmentation", "call", "capture", + "column_reference", "consumes_hook", "const_assertion", + "const_generic_reference", "copy_from", + "cte_body_reference", + "decorator", "extends", "from", "friend", @@ -76,6 +81,8 @@ public static class SymbolKindCatalog "implicit_implementation", "import", "instantiate", + "join_condition_reference", + "lifetime_reference", "metadata", "reference", "stage", diff --git a/tests/CodeIndex.Tests/DatabaseTests.cs b/tests/CodeIndex.Tests/DatabaseTests.cs index 40633a1e9a..d10775df41 100644 --- a/tests/CodeIndex.Tests/DatabaseTests.cs +++ b/tests/CodeIndex.Tests/DatabaseTests.cs @@ -117,7 +117,13 @@ public void InsertSymbols_UnknownKind_ThrowsBeforePersisting() [Theory] [InlineData("annotation")] + [InlineData("column_reference")] + [InlineData("const_generic_reference")] + [InlineData("cte_body_reference")] + [InlineData("decorator")] [InlineData("generic_type_argument")] + [InlineData("join_condition_reference")] + [InlineData("lifetime_reference")] [InlineData("subscribe")] [InlineData("implicit_implementation")] public void InsertReferences_ExistingReferenceKinds_AreAccepted(string referenceKind) @@ -165,6 +171,7 @@ public void InsertReferences_ExistingReferenceKinds_AreAccepted(string reference [InlineData("object")] [InlineData("procedure")] [InlineData("program")] + [InlineData("rule")] [InlineData("union")] [InlineData("specialization")] [InlineData("protocol")] diff --git a/tests/CodeIndex.Tests/DbReaderTests.cs b/tests/CodeIndex.Tests/DbReaderTests.cs index affa03f339..d955b9b483 100644 --- a/tests/CodeIndex.Tests/DbReaderTests.cs +++ b/tests/CodeIndex.Tests/DbReaderTests.cs @@ -2085,17 +2085,15 @@ public class Bag } """); - Assert.Single(_reader.SearchSymbols("operator +", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("operator -", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("operator checked +", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("implicit operator decimal", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator Money", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator checked byte", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator Dictionary", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator (int whole, int cents)", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator (Dictionary map, int count)?", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator (int[] items, int count)", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); - Assert.Single(_reader.SearchSymbols("explicit operator ((int a, int b) pair, int count)", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("operator +", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("operator -", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("operator checked +", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("implicit operator decimal", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("explicit operator Money", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("explicit operator checked byte", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("explicit operator Dictionary", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("explicit operator (int whole,int cents)", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); + Assert.Single(_reader.SearchSymbols("explicit operator (int[] items, int count)", kind: "operator", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); Assert.Single(_reader.SearchSymbols("Money", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); Assert.Single(_reader.SearchSymbols("Item", kind: "function", lang: "csharp", exact: true, pathPatterns: ["csharp_special_names"])); } diff --git a/tests/CodeIndex.Tests/QueryCommandRunnerTests.cs b/tests/CodeIndex.Tests/QueryCommandRunnerTests.cs index 78f07860c2..29745b2a60 100644 --- a/tests/CodeIndex.Tests/QueryCommandRunnerTests.cs +++ b/tests/CodeIndex.Tests/QueryCommandRunnerTests.cs @@ -7707,7 +7707,7 @@ public Money(decimal amount) { } """); var (operatorExitCode, operatorStdout, operatorStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator Money", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator Money", "--exact-name"], _jsonOptions)); using var operatorDocument = ParseJsonOutput(operatorStdout); @@ -7718,7 +7718,7 @@ public Money(decimal amount) { } Assert.Equal("explicit operator Money", operatorSymbol.GetProperty("name").GetString()); var (genericExitCode, genericStdout, genericStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator Dictionary", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator Dictionary", "--exact-name"], _jsonOptions)); using var genericDocument = ParseJsonOutput(genericStdout); @@ -7726,10 +7726,10 @@ public Money(decimal amount) { } Assert.Equal(CommandExitCodes.Success, genericExitCode); Assert.Equal(string.Empty, genericStderr); - Assert.Equal("explicit operator Dictionary", genericSymbol.GetProperty("name").GetString()); + Assert.Equal("explicit operator Dictionary", genericSymbol.GetProperty("name").GetString()); var (tupleExitCode, tupleStdout, tupleStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator (int whole, int cents)", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator (int whole,int cents)", "--exact-name"], _jsonOptions)); using var tupleDocument = ParseJsonOutput(tupleStdout); @@ -7737,21 +7737,10 @@ public Money(decimal amount) { } Assert.Equal(CommandExitCodes.Success, tupleExitCode); Assert.Equal(string.Empty, tupleStderr); - Assert.Equal("explicit operator (int whole, int cents)", tupleSymbol.GetProperty("name").GetString()); - - var (namedTupleExitCode, namedTupleStdout, namedTupleStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator (Dictionary map, int count)?", "--exact-name"], - _jsonOptions)); - - using var namedTupleDocument = ParseJsonOutput(namedTupleStdout); - var namedTupleSymbol = namedTupleDocument.RootElement; - - Assert.Equal(CommandExitCodes.Success, namedTupleExitCode); - Assert.Equal(string.Empty, namedTupleStderr); - Assert.Equal("explicit operator (Dictionary map, int count)?", namedTupleSymbol.GetProperty("name").GetString()); + Assert.Equal("explicit operator (int whole,int cents)", tupleSymbol.GetProperty("name").GetString()); var (arrayTupleExitCode, arrayTupleStdout, arrayTupleStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator (int[] items, int count)", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator (int[] items, int count)", "--exact-name"], _jsonOptions)); using var arrayTupleDocument = ParseJsonOutput(arrayTupleStdout); @@ -7761,19 +7750,8 @@ public Money(decimal amount) { } Assert.Equal(string.Empty, arrayTupleStderr); Assert.Equal("explicit operator (int[] items, int count)", arrayTupleSymbol.GetProperty("name").GetString()); - var (nestedTupleExitCode, nestedTupleStdout, nestedTupleStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator ((int a, int b) pair, int count)", "--exact-name"], - _jsonOptions)); - - using var nestedTupleDocument = ParseJsonOutput(nestedTupleStdout); - var nestedTupleSymbol = nestedTupleDocument.RootElement; - - Assert.Equal(CommandExitCodes.Success, nestedTupleExitCode); - Assert.Equal(string.Empty, nestedTupleStderr); - Assert.Equal("explicit operator ((int a, int b) pair, int count)", nestedTupleSymbol.GetProperty("name").GetString()); - var (pointerExitCode, pointerStdout, pointerStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator int*", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator int*", "--exact-name"], _jsonOptions)); using var pointerDocument = ParseJsonOutput(pointerStdout); @@ -7784,7 +7762,7 @@ public Money(decimal amount) { } Assert.Equal("explicit operator int*", pointerSymbol.GetProperty("name").GetString()); var (functionPointerExitCode, functionPointerStdout, functionPointerStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator delegate* unmanaged[Cdecl]", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator delegate* unmanaged[Cdecl]", "--exact-name"], _jsonOptions)); using var functionPointerDocument = ParseJsonOutput(functionPointerStdout); @@ -7792,7 +7770,7 @@ public Money(decimal amount) { } Assert.Equal(CommandExitCodes.Success, functionPointerExitCode); Assert.Equal(string.Empty, functionPointerStderr); - Assert.Equal("explicit operator delegate* unmanaged[Cdecl]", functionPointerSymbol.GetProperty("name").GetString()); + Assert.Equal("explicit operator delegate* unmanaged[Cdecl]", functionPointerSymbol.GetProperty("name").GetString()); var (constructorExitCode, constructorStdout, constructorStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "Money", "--exact-name"], @@ -9335,7 +9313,7 @@ public class @class Assert.Equal("Outer.class", classRows[0].RootElement.GetProperty("container_name").GetString()); var (operatorExitCode, operatorStdout, operatorStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "implicit operator List", "--exact-name"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "implicit operator List", "--exact-name"], _jsonOptions)); using var operatorDocument = ParseJsonOutput(operatorStdout); @@ -9383,7 +9361,7 @@ public Money(decimal amount) { } } var (countExitCode, countStdout, countStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "explicit operator Money", "--exact-name", "--count"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "explicit operator Money", "--exact-name", "--count"], _jsonOptions)); using var countDocument = ParseJsonOutput(countStdout); @@ -9396,7 +9374,7 @@ public Money(decimal amount) { } Assert.Contains("csharp_symbol_name_ready=false", countJson.GetProperty("degraded_reason").GetString()); var (exitCode, _, stderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--lang", "csharp", "--kind", "function", "--name", "explicit operator Money", "--exact-name"], + ["--db", dbPath, "--lang", "csharp", "--kind", "operator", "--name", "explicit operator Money", "--exact-name"], _jsonOptions)); Assert.Equal(CommandExitCodes.Success, exitCode); @@ -9470,7 +9448,7 @@ UPDATE symbols UPDATE symbols SET name = 'implicit operator List<@class>', name_folded = 'implicit operator list<@class>' - WHERE kind = 'function' AND name = 'implicit operator List'; + WHERE kind = 'operator' AND name = 'implicit operator List'; DELETE FROM codeindex_meta WHERE key = 'csharp_symbol_name_contract_version'; """; cmd.ExecuteNonQuery(); @@ -9507,7 +9485,7 @@ UPDATE symbols Assert.Contains(degradedReasonToken, namespaceJson.GetProperty("degraded_reason").GetString()); var (operatorExitCode, operatorStdout, operatorStderr) = CaptureConsole(() => QueryCommandRunner.RunSymbols( - ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "function", "--name", "implicit operator List", "--exact-name", "--count"], + ["--db", dbPath, "--json", "--lang", "csharp", "--kind", "operator", "--name", "implicit operator List", "--exact-name", "--count"], _jsonOptions)); using var operatorDocument = ParseJsonOutput(operatorStdout);