Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions changelog.d/unreleased/2047.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: fixed
issues:
- 2047
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Go.cs
- tests/CodeIndex.Tests/SymbolExtractorTests.cs
---

## English

- **Go embedded generic struct types are indexed (#2047)** — struct bodies now expose embedded generic types such as `Reader[T]` and `*pkg.Writer[U]` as import-kind symbols without treating ordinary named fields as embedded types.

## 日本語

- **Go struct の embedded generic type を index するようになりました (#2047)** — struct body 内の `Reader[T]` や `*pkg.Writer[U]` などを import-kind symbol として公開し、通常の named field は embedded type として扱いません。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2048.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2048
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Go.cs
- tests/CodeIndex.Tests/SymbolExtractorTests.cs
---

## English

- **Go blank identifiers are no longer indexed as properties (#2048)** — `var` and `const` declarations skip `_` while preserving ordinary names such as `_unused`.

## 日本語

- **Go の blank identifier を property として index しなくなりました (#2048)** — `var` / `const` 宣言では `_` を除外しつつ、`_unused` のような通常の名前は維持します。
17 changes: 17 additions & 0 deletions changelog.d/unreleased/2049.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
category: fixed
issues:
- 2049
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Go.cs
- tests/CodeIndex.Tests/SymbolExtractorTests.cs
---

## English

- **Go interface method signatures preserve type parameters (#2049)** — interface method extraction now recognizes bracketed method type parameters and stores the candidate method signature instead of the surrounding raw line.

## 日本語

- **Go interface method の signature が type parameter を保持するようになりました (#2049)** — interface method 抽出は bracket 付き method type parameter を認識し、周囲の raw line ではなく候補 method signature を保存します。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2050.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2050
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Go.cs
- tests/CodeIndex.Tests/SymbolExtractorTests.cs
---

## English

- **Go build directives and CGO imports are exposed as metadata (#2050)** — `//go:build` / `//go:test` comments are indexed as annotation symbols, and `import "C"` is classified as `cgo` instead of a regular import.

## 日本語

- **Go の build directive と CGO import を metadata として公開するようになりました (#2050)** — `//go:build` / `//go:test` comment は annotation symbol として index され、`import "C"` は通常 import ではなく `cgo` として分類されます。
167 changes: 161 additions & 6 deletions src/CodeIndex/Indexer/Symbols/SymbolExtractor.Go.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ private static bool TryHandleGoBlockLine(
{
var trimmed = line.TrimStart();

if (TryAddGoDirectiveSymbol(fileId, line, lineIndex, symbols, trimmed))
return true;

if (inImportBlock)
{
if (trimmed.Length == 0
Expand Down Expand Up @@ -83,7 +86,8 @@ private static bool TryAddGoTypeSymbol(
int lineIndex,
List<SymbolRecord> symbols,
string typeText,
ref int goTypeBodyDepth)
ref int goTypeBodyDepth,
ref string? goTypeBodyKind)
{
var normalizedTypeText = typeText.StartsWith("type", StringComparison.Ordinal)
? typeText["type".Length..].TrimStart()
Expand All @@ -99,7 +103,12 @@ private static bool TryAddGoTypeSymbol(
? "protocol"
: "class";
if (HasGoSymbol(symbols, fileId, lineIndex + 1, kind, name))
{
if (kind == "struct")
TryAddGoStructEmbeddedTypeSymbols(fileId, rawLine, lineIndex, symbols, ExtractGoInlineTypeBody(typeText));

return true;
}
var startColumn = rawLine.IndexOf(name, StringComparison.Ordinal);
if (startColumn < 0)
startColumn = rawLine.Length - rawLine.TrimStart().Length;
Expand All @@ -121,8 +130,17 @@ private static bool TryAddGoTypeSymbol(
},
rawLine);

if (kind is "struct" or "protocol")
if (kind == "struct")
{
TryAddGoStructEmbeddedTypeSymbols(fileId, rawLine, lineIndex, symbols, ExtractGoInlineTypeBody(typeText));
goTypeBodyDepth = CountGoBraceDelta(typeText);
goTypeBodyKind = goTypeBodyDepth > 0 ? kind : null;
}
else if (kind == "protocol")
{
goTypeBodyDepth = CountGoBraceDelta(typeText);
goTypeBodyKind = goTypeBodyDepth > 0 ? kind : null;
}

return true;
}
Expand All @@ -140,6 +158,9 @@ private static bool TryAddGoValueSymbol(

foreach (var name in match.Groups["names"].Value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
if (name == "_")
continue;

if (HasGoSymbol(symbols, fileId, lineIndex + 1, "property", name))
continue;

Expand Down Expand Up @@ -349,6 +370,7 @@ private static bool TryAddGoImportSymbol(
return true;

var name = match.Groups["name"].Value.Trim();
var kind = string.Equals(name, @"""C""", StringComparison.Ordinal) ? "cgo" : "import";
var startColumn = rawLine.IndexOf(name, StringComparison.Ordinal);
if (startColumn < 0)
startColumn = rawLine.IndexOf(importText, StringComparison.Ordinal);
Expand All @@ -362,7 +384,7 @@ private static bool TryAddGoImportSymbol(
new SymbolRecord
{
FileId = fileId,
Kind = "import",
Kind = kind,
Name = name,
Line = lineIndex + 1,
StartLine = lineIndex + 1,
Expand All @@ -374,6 +396,46 @@ private static bool TryAddGoImportSymbol(
return true;
}

private static bool TryAddGoDirectiveSymbol(
long fileId,
string rawLine,
int lineIndex,
List<SymbolRecord> symbols,
string trimmed)
{
if (!trimmed.StartsWith("//go:build", StringComparison.Ordinal)
&& !trimmed.StartsWith("//go:test", StringComparison.Ordinal))
{
return false;
}

var name = trimmed[2..].Trim();
if (HasGoSymbol(symbols, fileId, lineIndex + 1, "annotation", name))
return true;

var startColumn = rawLine.IndexOf("//go:", StringComparison.Ordinal);
if (startColumn < 0)
startColumn = rawLine.Length - rawLine.TrimStart().Length;

AddSymbolRecord(
symbols,
cssSeenSymbols: null,
lineIndex + 1,
new SymbolRecord
{
FileId = fileId,
Kind = "annotation",
Name = name,
Line = lineIndex + 1,
StartLine = lineIndex + 1,
StartColumn = startColumn,
EndLine = lineIndex + 1,
Signature = trimmed,
},
rawLine);
return true;
}

private static void ExtractGoInterfaceMethods(long fileId, string[] lines, List<SymbolRecord> symbols)
{
var awaitingInterfaceBody = false;
Expand Down Expand Up @@ -527,7 +589,7 @@ private static bool TryAddGoInterfaceMethodSymbol(
StartLine = lineIndex + 1,
StartColumn = startColumn,
EndLine = lineIndex + 1,
Signature = rawLine.Trim(),
Signature = candidate.Trim(),
},
rawLine);
return true;
Expand Down Expand Up @@ -579,6 +641,91 @@ private static bool TryAddGoInterfaceEmbeddedTypeSymbol(
return true;
}

private static string ExtractGoInlineTypeBody(string typeText)
{
var openBraceIndex = typeText.IndexOf('{');
if (openBraceIndex < 0)
return string.Empty;

var body = typeText[(openBraceIndex + 1)..];
var closeBraceIndex = body.LastIndexOf('}');
return closeBraceIndex >= 0 ? body[..closeBraceIndex] : body;
}

private static void TryAddGoStructEmbeddedTypeSymbols(
long fileId,
string rawLine,
int lineIndex,
List<SymbolRecord> symbols,
string bodyText)
{
if (string.IsNullOrWhiteSpace(bodyText))
return;

foreach (var segment in bodyText.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
var candidate = segment;
var trailingBraceIndex = candidate.IndexOf('}');
if (trailingBraceIndex >= 0)
candidate = candidate[..trailingBraceIndex].TrimEnd();

var lineCommentIndex = candidate.IndexOf("//", StringComparison.Ordinal);
if (lineCommentIndex >= 0)
candidate = candidate[..lineCommentIndex].TrimEnd();

var blockCommentIndex = candidate.IndexOf("/*", StringComparison.Ordinal);
if (blockCommentIndex >= 0)
candidate = candidate[..blockCommentIndex].TrimEnd();

var tagIndex = candidate.IndexOf('`');
if (tagIndex >= 0)
candidate = candidate[..tagIndex].TrimEnd();

if (candidate.Length == 0)
continue;

TryAddGoStructEmbeddedTypeSymbol(fileId, rawLine, lineIndex, symbols, candidate);
}
}

private static bool TryAddGoStructEmbeddedTypeSymbol(
long fileId,
string rawLine,
int lineIndex,
List<SymbolRecord> symbols,
string candidate)
{
var match = GoStructEmbeddedTypeRegex.Match(candidate);
if (!match.Success)
return false;

var name = match.Groups["name"].Value.Trim();
if (name.Length == 0 || HasGoSymbol(symbols, fileId, lineIndex + 1, "import", name))
return true;

var startColumn = rawLine.IndexOf(name, StringComparison.Ordinal);
if (startColumn < 0)
startColumn = rawLine.Length - rawLine.TrimStart().Length;

AddSymbolRecord(
symbols,
cssSeenSymbols: null,
lineIndex + 1,
new SymbolRecord
{
FileId = fileId,
Kind = "import",
Name = name,
Line = lineIndex + 1,
StartLine = lineIndex + 1,
StartColumn = startColumn,
EndLine = lineIndex + 1,
Signature = candidate.Trim(),
},
rawLine);
return true;
}

private static bool HasGoSymbol(List<SymbolRecord> symbols, long fileId, int lineNumber, string kind, string name)
{
return symbols.Any(symbol =>
Expand Down Expand Up @@ -820,6 +967,7 @@ private static void ExtractGoGroupedDeclarations(long fileId, string[] lines, Li
string? blockKind = null;
ExtractGoInterfaceMethods(fileId, lines, symbols);
var typeBodyDepth = 0;
string? typeBodyKind = null;
var goBlockDepth = 0;
var goBlockInBlockComment = false;
var goBlockInRawString = false;
Expand All @@ -831,9 +979,14 @@ private static void ExtractGoGroupedDeclarations(long fileId, string[] lines, Li

if (typeBodyDepth > 0)
{
if (typeBodyKind == "struct")
TryAddGoStructEmbeddedTypeSymbols(fileId, line, i, symbols, trimmed);

typeBodyDepth += CountGoBraceDelta(line);
if (typeBodyDepth < 0)
typeBodyDepth = 0;
if (typeBodyDepth == 0)
typeBodyKind = null;
continue;
}

Expand All @@ -849,13 +1002,15 @@ private static void ExtractGoGroupedDeclarations(long fileId, string[] lines, Li
|| trimmed.StartsWith("//", StringComparison.Ordinal)
|| trimmed.StartsWith("/*", StringComparison.Ordinal))
{
TryAddGoDirectiveSymbol(fileId, line, i, symbols, trimmed);
continue;
}

if (trimmed.StartsWith(")", StringComparison.Ordinal))
{
blockKind = null;
typeBodyDepth = 0;
typeBodyKind = null;
continue;
}

Expand All @@ -864,7 +1019,7 @@ private static void ExtractGoGroupedDeclarations(long fileId, string[] lines, Li
switch (blockKind)
{
case "type":
TryAddGoTypeSymbol(fileId, line, i, symbols, trimmed, ref typeBodyDepth);
TryAddGoTypeSymbol(fileId, line, i, symbols, trimmed, ref typeBodyDepth, ref typeBodyKind);
break;
case "const":
case "var":
Expand Down Expand Up @@ -910,7 +1065,7 @@ private static void ExtractGoGroupedDeclarations(long fileId, string[] lines, Li

if (trimmed.StartsWith("type", StringComparison.Ordinal))
{
TryAddGoTypeSymbol(fileId, line, i, symbols, trimmed, ref typeBodyDepth);
TryAddGoTypeSymbol(fileId, line, i, symbols, trimmed, ref typeBodyDepth, ref typeBodyKind);
continue;
}

Expand Down
5 changes: 4 additions & 1 deletion src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,14 @@ public static int GetContractVersion(string? lang)
@"^\s*(?:type\s+)?\w+(?:\[[^\]]+\])?\s+interface\b",
RegexOptions.Compiled | RegexOptions.CultureInvariant);
private static readonly Regex GoInterfaceMethodRegex = new(
@"^\s*(?<name>[A-Za-z_]\w*)\s*\(",
@"^\s*(?<name>[A-Za-z_]\w*)\s*(?:\[[^\]\r\n]+\])?\s*\(",
RegexOptions.Compiled | RegexOptions.CultureInvariant);
private static readonly Regex GoInterfaceEmbeddedTypeRegex = new(
@"^\s*(?:~\s*)?(?<name>[A-Za-z_]\w*(?:\s*\.\s*[A-Za-z_]\w*)*)(?:\[[^\]\r\n]+\])?\s*$",
RegexOptions.Compiled | RegexOptions.CultureInvariant);
private static readonly Regex GoStructEmbeddedTypeRegex = new(
@"^\s*\*?\s*(?<name>[A-Za-z_]\w*(?:\s*\.\s*[A-Za-z_]\w*)*)(?:\[[^\]\r\n]+\])?\s*$",
RegexOptions.Compiled | RegexOptions.CultureInvariant);
private static readonly HashSet<string> GoInterfaceEmbeddedTypeBlacklist = new(StringComparer.Ordinal)
{
"bool",
Expand Down
Loading
Loading