Skip to content
Closed
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
18 changes: 18 additions & 0 deletions changelog.d/unreleased/1976.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
category: fixed
issues:
- 1976
affected:
- src/CodeIndex/Database/DbReader.cs
- src/CodeIndex/Models/SymbolKindCatalog.cs
- src/CodeIndex/Indexer/References/Languages/SwiftReferenceExtractor.cs
- src/CodeIndex/Indexer/References/Languages/TypeScriptReferenceExtractor.cs
---

## English

- **Type alias targets now participate in graph traversal (#1976)** — Swift and TypeScript type alias RHS references now emit explicit alias-target edges so graph queries can continue from an alias symbol to its underlying type.

## 日本語

- **型エイリアスの参照先が graph traversal に参加するようになりました (#1976)** — Swift と TypeScript の type alias RHS が明示的な alias-target edge を出すようになり、graph query が alias symbol から underlying type へ辿れるようになりました。
4 changes: 3 additions & 1 deletion src/CodeIndex/Database/DbReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ ELSE 0
// Razor の `razor_event_binding`、React の `consumes_hook`、C++ の `friend` は依存関係 graph query に含める。
// C# closure の `capture` は lambda 本体から外側 local への依存であり、impact に参加する。
// C# generic invocation type arguments are included when tied to an actual call (#2062).
internal const string CallGraphReferenceKindsSql = "('augmentation', 'call', 'instantiate', 'generic_type_argument', 'subscribe', 'unsubscribe', 'razor_event_binding', 'friend', 'consumes_hook', 'capture')";
// Type alias target edges are explicit indirection edges, allowing graph walks to continue
// from an alias symbol to its underlying type without promoting ordinary annotations (#1976).
internal const string CallGraphReferenceKindsSql = "('augmentation', 'call', 'instantiate', 'generic_type_argument', 'subscribe', 'unsubscribe', 'razor_event_binding', 'friend', 'consumes_hook', 'capture', 'type_alias_target')";
private const string SyntheticTopLevelCallerName = "<top-level>";
private const string SyntheticTopLevelCallerKind = "function";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1033,16 +1033,54 @@ private static void EmitTypealiasRhsTypeReferences(
if (typeEnd <= typeStart)
return;

var rhsExpression = preparedLine.Substring(typeStart, typeEnd - typeStart);
var rhsContainer = new SymbolRecord
{
Kind = "typealias",
Name = ExtractTypealiasName(preparedLine, typealiasIndex + "typealias".Length),
};
var typeReferenceContainer = resolveContainerForColumn(typeStart);
TypedLanguageReferenceExtractor.EmitTypeExpressionReferences(
preparedLine.Substring(typeStart, typeEnd - typeStart),
rhsExpression,
typeStart,
"swift",
references,
seen,
fileId,
context,
lineNumber,
resolveContainerForColumn(typeStart));
typeReferenceContainer);
ReferenceExtractor.EmitTypeAliasTargetExpressionReferences(
rhsExpression,
typeStart,
"swift",
references,
seen,
fileId,
context,
lineNumber,
rhsContainer);
}

private static string ExtractTypealiasName(string line, int nameStart)
{
while (nameStart < line.Length && char.IsWhiteSpace(line[nameStart]))
nameStart++;
if (nameStart >= line.Length)
return string.Empty;

if (line[nameStart] == '`')
{
var close = line.IndexOf('`', nameStart + 1);
if (close > nameStart)
return line.Substring(nameStart, close - nameStart + 1);
}

var nameEnd = nameStart;
while (nameEnd < line.Length && (line[nameEnd] == '_' || char.IsLetterOrDigit(line[nameEnd])))
nameEnd++;

return line.Substring(nameStart, nameEnd - nameStart);
}

private static void EmitAssociatedTypeReferences(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1267,16 +1267,42 @@ private static void EmitTypeAliasTypeReferences(
if (rhsEnd <= rhsStart)
return;

var rhsExpression = preparedLine.Substring(rhsStart, rhsEnd - rhsStart);
var rhsContainer = new SymbolRecord
{
Kind = "typealias",
Name = ExtractTypeAliasName(preparedLine, nameEnd),
};
var typeReferenceContainer = resolveContainerForColumn(rhsStart);
TypedLanguageReferenceExtractor.EmitTypeExpressionReferences(
preparedLine.Substring(rhsStart, rhsEnd - rhsStart),
rhsExpression,
rhsStart,
"typescript",
references,
seen,
fileId,
context,
lineNumber,
resolveContainerForColumn(rhsStart));
typeReferenceContainer);
ReferenceExtractor.EmitTypeAliasTargetExpressionReferences(
rhsExpression,
rhsStart,
"typescript",
references,
seen,
fileId,
context,
lineNumber,
rhsContainer);
}

private static string ExtractTypeAliasName(string line, int nameEnd)
{
var nameStart = nameEnd;
while (nameStart > 0 && IsTypeScriptIdentifierPart(line[nameStart - 1]))
nameStart--;

return line.Substring(nameStart, nameEnd - nameStart);
}

private static bool TryFindTypeAliasShape(string line, out int nameEnd, out int assignmentIndex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1130,11 +1130,12 @@ private static void AddTypeExpressionSegmentsForLanguage(
string context,
int lineNumber,
SymbolRecord? container,
IReadOnlySet<string>? ignoredSegments = null)
IReadOnlySet<string>? ignoredSegments = null,
string referenceKind = "type_reference")
{
if (language == "typescript")
{
AddTypeScriptTypeExpressionSegments(
AddTypeScriptTypeExpressionSegmentsCore(
references,
seen,
fileId,
Expand Down Expand Up @@ -1167,7 +1168,8 @@ internal static void AddTypeScriptTypeExpressionSegments(
int expressionStartInLine,
string context,
int lineNumber,
SymbolRecord? container)
SymbolRecord? container,
string referenceKind = "type_reference")
{
if (TypedLanguageReferenceExtractor.TryEmitTypeScriptFunctionTypeExpressionReferences(
expression,
Expand Down Expand Up @@ -1281,7 +1283,8 @@ private static int SkipTypeScriptTemplateLiteral(
int expressionStartInLine,
string context,
int lineNumber,
SymbolRecord? container)
SymbolRecord? container,
string referenceKind = "type_reference")
{
int i = start + 1;
while (i < text.Length)
Expand Down Expand Up @@ -1850,11 +1853,12 @@ internal static void AddTypeExpressionSegments(
int lineNumber,
SymbolRecord? container,
string language,
IReadOnlySet<string>? ignoredSegments = null)
IReadOnlySet<string>? ignoredSegments = null,
string referenceKind = "type_reference")
{
if (language == "typescript")
{
AddTypeScriptTypeExpressionSegments(
AddTypeScriptTypeExpressionSegmentsCore(
references,
seen,
fileId,
Expand All @@ -1863,7 +1867,8 @@ internal static void AddTypeExpressionSegments(
context,
lineNumber,
container,
ignoredSegments);
ignoredSegments,
referenceKind);
return;
}

Expand Down Expand Up @@ -1906,7 +1911,7 @@ internal static void AddTypeExpressionSegments(
continue;
}

AddReference(references, seen, fileId, rustSegment, expressionStartInLine + rustSegmentStart, "type_reference", context, lineNumber, container);
AddReference(references, seen, fileId, rustSegment, expressionStartInLine + rustSegmentStart, referenceKind, context, lineNumber, container);
i--;
continue;
}
Expand Down Expand Up @@ -1934,7 +1939,8 @@ internal static void AddTypeExpressionSegments(
lineNumber,
container,
language,
ignoredSegments: ignoredSegments);
ignoredSegments: ignoredSegments,
referenceKind: referenceKind);
i = closeIndex;
continue;
}
Expand All @@ -1956,7 +1962,8 @@ internal static void AddTypeExpressionSegments(
lineNumber,
container,
language,
ignoredSegments: ignoredSegments);
ignoredSegments: ignoredSegments,
referenceKind: referenceKind);
i = closeIndex;
continue;
}
Expand Down Expand Up @@ -2006,7 +2013,7 @@ internal static void AddTypeExpressionSegments(
continue;
}

AddTypeReferenceSegment(references, seen, fileId, segment, expressionStartInLine + segmentStart, context, lineNumber, container, language, isEscapedCSharpIdentifier, ignoredSegments);
AddTypeReferenceSegment(references, seen, fileId, segment, expressionStartInLine + segmentStart, context, lineNumber, container, language, isEscapedCSharpIdentifier, ignoredSegments, referenceKind);
i--;
}
}
Expand Down Expand Up @@ -2046,7 +2053,7 @@ private static bool IsSwiftMetatypeSuffixSegment(string expression, int segmentS
return previous >= 0 && expression[previous] == '.';
}

private static void AddTypeScriptTypeExpressionSegments(
private static void AddTypeScriptTypeExpressionSegmentsCore(
List<ReferenceRecord> references,
HashSet<string> seen,
long fileId,
Expand All @@ -2055,7 +2062,8 @@ private static void AddTypeScriptTypeExpressionSegments(
string context,
int lineNumber,
SymbolRecord? container,
IReadOnlySet<string>? ignoredSegments = null)
IReadOnlySet<string>? ignoredSegments = null,
string referenceKind = "type_reference")
{
ignoredSegments ??= TypeScriptTypeExpressionIgnoredSegments;

Expand All @@ -2081,7 +2089,8 @@ private static void AddTypeScriptTypeExpressionSegments(
seen,
fileId,
container,
ignoredSegments);
ignoredSegments,
referenceKind);
continue;
}

Expand Down Expand Up @@ -2115,7 +2124,8 @@ private static void AddTypeScriptTypeExpressionSegments(
lineNumber,
container,
"typescript",
ignoredSegments: ignoredSegments);
ignoredSegments: ignoredSegments,
referenceKind: referenceKind);
}
}

Expand All @@ -2140,7 +2150,8 @@ private static int ScanTypeScriptTemplateLiteralForTypeExpression(
HashSet<string> seen,
long fileId,
SymbolRecord? container,
IReadOnlySet<string>? ignoredSegments)
IReadOnlySet<string>? ignoredSegments,
string referenceKind = "type_reference")
{
int i = startIndex + 1;
while (i < expression.Length)
Expand All @@ -2165,7 +2176,7 @@ private static int ScanTypeScriptTemplateLiteralForTypeExpression(
if (holeEnd < 0)
return expression.Length;

AddTypeScriptTypeExpressionSegments(
AddTypeScriptTypeExpressionSegmentsCore(
references,
seen,
fileId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,30 @@ internal static void AddTypeReferenceSegment(
});
}

internal static void EmitTypeAliasTargetExpressionReferences(
string expression,
int expressionStartInLine,
string language,
List<ReferenceRecord> references,
HashSet<string> seen,
long fileId,
string context,
int lineNumber,
SymbolRecord? container)
{
AddTypeExpressionSegments(
references,
seen,
fileId,
expression,
expressionStartInLine,
context,
lineNumber,
container,
language,
referenceKind: "type_alias_target");
}

private static SymbolRecord? FindInnermostContainer(IReadOnlyList<SymbolRecord> candidates, int lineNumber)
{
foreach (var candidate in candidates)
Expand Down
1 change: 1 addition & 0 deletions src/CodeIndex/Models/SymbolKindCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public static class SymbolKindCatalog
"stage",
"razor_event_binding",
"subscribe",
"type_alias_target",
"type_reference",
"unsubscribe",
"use",
Expand Down
15 changes: 15 additions & 0 deletions tests/CodeIndex.Tests/ReferenceExtractorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5752,6 +5752,11 @@ public void Extract_TypeScriptTypeAliasGenericDefaults_EmitsDefaultAndRhsTypeRef
reference.SymbolName == "Record"
&& reference.ReferenceKind == "type_reference"
&& reference.Context == "type Dict<K = DefaultKey, V = DefaultValue> = Record<K, V>;");
Assert.Contains(references, reference =>
reference.SymbolName == "Record"
&& reference.ReferenceKind == "type_alias_target"
&& reference.ContainerKind == "typealias"
&& reference.ContainerName == "Dict");
}

[Fact]
Expand Down Expand Up @@ -26180,6 +26185,16 @@ struct Failure {}
Assert.Contains(references, reference =>
reference.SymbolName == "Failure"
&& reference.ReferenceKind == "type_reference");
Assert.Contains(references, reference =>
reference.SymbolName == "Request"
&& reference.ReferenceKind == "type_alias_target"
&& reference.ContainerKind == "typealias"
&& reference.ContainerName == "Loader");
Assert.Contains(references, reference =>
reference.SymbolName == "Result"
&& reference.ReferenceKind == "type_alias_target"
&& reference.ContainerKind == "typealias"
&& reference.ContainerName == "LoadResult");
}

[Fact]
Expand Down
Loading