Skip to content

Commit abf8067

Browse files
authored
Merge pull request #83427 from hamishknight/compound-interest
[Index] Fix a couple of `reportRelatedTypeRef` issues
2 parents 3195c28 + 99f6341 commit abf8067

File tree

3 files changed

+187
-42
lines changed

3 files changed

+187
-42
lines changed

lib/Index/Index.cpp

Lines changed: 125 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,17 +1028,46 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
10281028

10291029
bool reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isImplicit, SymbolRoleSet Relations, Decl *Related);
10301030

1031-
/// Report references for dependent types
1031+
/// Report a related type relation for a given TypeRepr.
10321032
///
1033-
/// NOTE: If the dependent type is a typealias, report the underlying types as well.
1033+
/// NOTE: If the dependent type is a typealias, report the underlying types as
1034+
/// well.
1035+
///
1036+
/// \param TR The type being referenced.
1037+
/// \param Relations The relationship between the referenced type and the
1038+
/// passed Decl.
1039+
/// \param Related The Decl that is referencing the type.
1040+
/// \param Implicit Whether the reference is implicit, such as for a
1041+
/// typealias' underlying type.
1042+
/// \param ParentLoc The parent location of the reference that should be used
1043+
/// for implicit references.
1044+
bool reportRelatedTypeRepr(const TypeRepr *TR, SymbolRoleSet Relations,
1045+
Decl *Related, bool Implicit, SourceLoc ParentLoc);
1046+
1047+
/// Report a related type relation for a Type at a given location.
10341048
///
10351049
/// \param Ty The type being referenced.
1036-
/// \param Relations The relationship between the referenced type and the passed Decl.
1050+
/// \param Relations The relationship between the referenced type and the
1051+
/// passed Decl.
1052+
/// \param Related The Decl that is referencing the type.
1053+
/// \param Implicit Whether the reference is implicit, such as for a
1054+
/// typealias' underlying type.
1055+
/// \param Loc The location of the reference.
1056+
bool reportRelatedType(Type Ty, SymbolRoleSet Relations, Decl *Related,
1057+
bool Implicit, SourceLoc Loc);
1058+
1059+
/// Report references for dependent types.
1060+
///
1061+
/// NOTE: If the dependent type is a typealias, report the underlying types as
1062+
/// well.
1063+
///
1064+
/// \param TL The type being referenced.
1065+
/// \param Relations The relationship between the referenced type and the
1066+
/// passed Decl.
10371067
/// \param Related The Decl that is referencing the type.
1038-
/// \param isImplicit Whether the reference is implicit, such as for a typealias' underlying type.
1039-
/// \param Loc The location of the reference, otherwise the location of the TypeLoc is used.
1040-
bool reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet Relations, Decl *Related,
1041-
bool isImplicit=false, SourceLoc Loc={});
1068+
bool reportRelatedTypeRef(const TypeLoc &TL, SymbolRoleSet Relations,
1069+
Decl *Related);
1070+
10421071
bool reportInheritedTypeRefs(InheritedTypes Inherited, Decl *Inheritee);
10431072

10441073
bool reportPseudoGetterDecl(VarDecl *D) {
@@ -1477,58 +1506,113 @@ bool IndexSwiftASTWalker::reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isI
14771506
bool IndexSwiftASTWalker::reportInheritedTypeRefs(InheritedTypes Inherited,
14781507
Decl *Inheritee) {
14791508
for (auto Base : Inherited.getEntries()) {
1509+
// Suppressed conformances aren't considered base types.
1510+
if (Base.isSuppressed())
1511+
continue;
14801512
if (!reportRelatedTypeRef(Base, (SymbolRoleSet) SymbolRole::RelationBaseOf, Inheritee))
14811513
return false;
14821514
}
14831515
return true;
14841516
}
14851517

1486-
bool IndexSwiftASTWalker::reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet Relations,
1487-
Decl *Related, bool Implicit, SourceLoc Loc) {
1488-
if (auto *composite = llvm::dyn_cast_or_null<CompositionTypeRepr>(Ty.getTypeRepr())) {
1489-
SourceLoc IdLoc = Loc.isValid() ? Loc : composite->getSourceLoc();
1518+
bool IndexSwiftASTWalker::reportRelatedTypeRepr(const TypeRepr *TR,
1519+
SymbolRoleSet Relations,
1520+
Decl *Related, bool Implicit,
1521+
SourceLoc ParentLoc) {
1522+
// Look through parens/specifiers/attributes.
1523+
while (true) {
1524+
if (TR->isParenType()) {
1525+
TR = TR->getWithoutParens();
1526+
continue;
1527+
}
1528+
if (auto *SPR = dyn_cast<SpecifierTypeRepr>(TR)) {
1529+
TR = SPR->getBase();
1530+
continue;
1531+
}
1532+
if (auto *ATR = dyn_cast<AttributedTypeRepr>(TR)) {
1533+
TR = ATR->getTypeRepr();
1534+
continue;
1535+
}
1536+
break;
1537+
}
1538+
// NOTE: We don't yet handle InverseTypeRepr since we don't have an inverse
1539+
// relation for inheritance.
1540+
1541+
if (auto *composite = dyn_cast<CompositionTypeRepr>(TR)) {
14901542
for (auto *Type : composite->getTypes()) {
1491-
if (!reportRelatedTypeRef(Type, Relations, Related, /*isImplicit=*/Implicit, IdLoc))
1543+
if (!reportRelatedTypeRepr(Type, Relations, Related, Implicit,
1544+
ParentLoc)) {
14921545
return false;
1546+
}
14931547
}
1548+
}
1549+
auto *declRefTR = dyn_cast<DeclRefTypeRepr>(TR);
1550+
if (!declRefTR)
1551+
return true;
14941552

1553+
auto *VD = declRefTR->getBoundDecl();
1554+
if (!VD)
14951555
return true;
1496-
} else if (auto *declRefTR = dyn_cast_or_null<DeclRefTypeRepr>(Ty.getTypeRepr())) {
1497-
SourceLoc IdLoc = Loc.isValid() ? Loc : declRefTR->getLoc();
1498-
NominalTypeDecl *NTD = nullptr;
1499-
bool isImplicit = Implicit;
1500-
if (auto *VD = declRefTR->getBoundDecl()) {
1501-
if (auto *TAD = dyn_cast<TypeAliasDecl>(VD)) {
1502-
IndexSymbol Info;
1503-
if (isImplicit)
1504-
Info.roles |= (unsigned)SymbolRole::Implicit;
1505-
if (!reportRef(TAD, IdLoc, Info, std::nullopt))
1506-
return false;
1507-
if (auto Ty = TAD->getUnderlyingType()) {
1508-
NTD = Ty->getAnyNominal();
1509-
isImplicit = true;
1510-
}
15111556

1512-
if (isa_and_nonnull<CompositionTypeRepr>(TAD->getUnderlyingTypeRepr())) {
1513-
TypeLoc TL(TAD->getUnderlyingTypeRepr(), TAD->getUnderlyingType());
1514-
if (!reportRelatedTypeRef(TL, Relations, Related, /*isImplicit=*/true, IdLoc))
1515-
return false;
1516-
}
1517-
} else {
1518-
NTD = dyn_cast<NominalTypeDecl>(VD);
1519-
}
1557+
SourceLoc IdLoc = ParentLoc.isValid() ? ParentLoc : declRefTR->getLoc();
1558+
if (auto *TAD = dyn_cast<TypeAliasDecl>(VD)) {
1559+
IndexSymbol Info;
1560+
if (Implicit)
1561+
Info.roles |= (unsigned)SymbolRole::Implicit;
1562+
if (!reportRef(TAD, IdLoc, Info, std::nullopt))
1563+
return false;
1564+
1565+
// Recurse into the underlying type and report any found references as
1566+
// implicit references at the location of the typealias reference.
1567+
if (auto *UTR = TAD->getUnderlyingTypeRepr()) {
1568+
return reportRelatedTypeRepr(UTR, Relations, Related,
1569+
/*Implicit*/ true, /*ParentLoc*/ IdLoc);
15201570
}
1521-
if (NTD) {
1522-
if (!reportRelatedRef(NTD, IdLoc, isImplicit, Relations, Related))
1571+
// If we don't have a TypeRepr available, this is a typealias in another
1572+
// module, consult the computed underlying type.
1573+
return reportRelatedType(TAD->getUnderlyingType(), Relations, Related,
1574+
/*Implicit*/ true, /*ParentLoc*/ IdLoc);
1575+
}
1576+
if (auto *NTD = dyn_cast<NominalTypeDecl>(VD)) {
1577+
if (!reportRelatedRef(NTD, IdLoc, Implicit, Relations, Related))
1578+
return false;
1579+
}
1580+
return true;
1581+
}
1582+
1583+
bool IndexSwiftASTWalker::reportRelatedType(Type Ty, SymbolRoleSet Relations,
1584+
Decl *Related, bool Implicit,
1585+
SourceLoc Loc) {
1586+
// Try decompose a protocol composition.
1587+
if (auto *PCT = Ty->getAs<ProtocolCompositionType>()) {
1588+
for (auto member : PCT->getMembers()) {
1589+
if (!reportRelatedType(member, Relations, Related, Implicit, Loc))
15231590
return false;
15241591
}
15251592
return true;
15261593
}
15271594

1528-
if (Ty.getType()) {
1529-
if (auto nominal = Ty.getType()->getAnyNominal())
1530-
if (!reportRelatedRef(nominal, Ty.getLoc(), /*isImplicit=*/false, Relations, Related))
1531-
return false;
1595+
if (auto *nominal = Ty->getAnyNominal()) {
1596+
if (!reportRelatedRef(nominal, Loc, Implicit, Relations, Related))
1597+
return false;
1598+
}
1599+
return true;
1600+
}
1601+
1602+
bool IndexSwiftASTWalker::reportRelatedTypeRef(const TypeLoc &TL,
1603+
SymbolRoleSet Relations,
1604+
Decl *Related) {
1605+
// If we have a TypeRepr, prefer that since it lets us match up source
1606+
// locations with the code the user wrote.
1607+
if (auto *TR = TL.getTypeRepr()) {
1608+
return reportRelatedTypeRepr(TR, Relations, Related, /*Implicit*/ false,
1609+
/*ParentLoc*/ SourceLoc());
1610+
}
1611+
// Otherwise fall back to reporting the Type, this is necessary when indexing
1612+
// swiftmodules.
1613+
if (auto Ty = TL.getType()) {
1614+
return reportRelatedType(Ty, Relations, Related,
1615+
/*Implicit*/ false, SourceLoc());
15321616
}
15331617
return true;
15341618
}

test/Index/conformances.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ struct DirectConf: P1 { // CHECK: [[@LINE]]:8 | struct/Swift | DirectConf | [[Di
1010
// CHECK-NEXT: RelChild | struct/Swift | DirectConf | [[DirectConf_USR]]
1111
}
1212

13+
struct LookThroughReprs: (@unchecked (Sendable)) {}
14+
// CHECK: [[@LINE-1]]:39 | protocol/Swift | Sendable | s:s8SendableP | Ref,RelBase | rel: 1
15+
// CHECK-NEXT: RelBase | struct/Swift | LookThroughReprs | s:14swift_ide_test16LookThroughReprsV
16+
17+
// No RelBase relation here since `Copyable` isn't a base type. Also make sure
18+
// we don't put a reference at the `~`.
19+
struct NonCopyable: ~Copyable {}
20+
// CHECK-NOT: [[@LINE-1]]:21
21+
// CHECK: [[@LINE-2]]:22 | protocol/Swift | Copyable | s:s8CopyableP | Ref | rel: 0
22+
// CHECK-NOT: [[@LINE-3]]:21
23+
24+
protocol NonCopyableProto: ~Copyable {}
25+
26+
struct AlsoNonCopyable: NonCopyableProto & ~Copyable {}
27+
// CHECK: [[@LINE-1]]:25 | protocol/Swift | NonCopyableProto | s:14swift_ide_test16NonCopyableProtoP | Ref,RelBase | rel: 1
28+
// CHECK-NEXT: RelBase | struct/Swift | AlsoNonCopyable | s:14swift_ide_test15AlsoNonCopyableV
29+
// CHECK-NEXT: [[@LINE-3]]:45 | protocol/Swift | Copyable | s:s8CopyableP | Ref | rel: 0
30+
1331
struct ConfFromExtension {}
1432
extension ConfFromExtension: P1 { // CHECK: [[@LINE]]:11 | extension/ext-struct/Swift | ConfFromExtension | [[ConfFromExtension_ext_USR:.*]] | Def
1533
func foo() {} // CHECK: [[@LINE]]:8 | instance-method/Swift | foo() | [[ConfFromExtension_ext_foo_USR:.*]] | Def,RelChild,RelOver | rel: 2
@@ -81,7 +99,7 @@ class SubMultiConf: BaseMultiConf,P2,P1,P3 { // CHECK: [[@LINE]]:7 | class/Swift
8199

82100
class CompositionType: BaseMultiConf & P1 { // CHECK: [[@LINE]]:7 | class/Swift | CompositionType | [[CompositionType_USR:.*]] | Def
83101
// CHECK: [[@LINE-1]]:24 | class/Swift | BaseMultiConf | [[BaseMultiConf_USR]] | Ref,RelBase | rel: 1
84-
// CHECK: [[@LINE-2]]:24 | protocol/Swift | P1 | [[P1_USR]] | Ref,RelBase | rel: 1
102+
// CHECK: [[@LINE-2]]:40 | protocol/Swift | P1 | [[P1_USR]] | Ref,RelBase | rel: 1
85103
func foo() {}
86104
}
87105

test/Index/index_imported.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file --leading-lines %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/Lib.swiftmodule %t/Lib.swift -module-name Lib
5+
// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %t/main.swift -module-to-print Lib -I %t | %FileCheck %s --check-prefix LIB
6+
// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %t/main.swift -I %t | %FileCheck %s
7+
8+
//--- Lib.swift
9+
10+
public protocol P {}
11+
public protocol Q {}
12+
public protocol R {}
13+
14+
public typealias X = Q & R
15+
16+
public struct S: X & P {}
17+
// LIB: 0:0 | protocol/Swift | Q | s:3Lib1QP | Ref,RelBase | rel: 1
18+
// LIB-NEXT: RelBase | struct/Swift | S | s:3Lib1SV
19+
// LIB-NEXT: 0:0 | protocol/Swift | R | s:3Lib1RP | Ref,RelBase | rel: 1
20+
// LIB-NEXT: RelBase | struct/Swift | S | s:3Lib1SV
21+
// LIB-NEXT: 0:0 | protocol/Swift | P | s:3Lib1PP | Ref,RelBase | rel: 1
22+
// LIB-NEXT: RelBase | struct/Swift | S | s:3Lib1SV
23+
24+
public protocol NonCopyableProto: ~Copyable {}
25+
public struct NonCopyable: NonCopyableProto & ~Copyable {}
26+
// LIB: 0:0 | protocol/Swift | NonCopyableProto | s:3Lib16NonCopyableProtoP | Ref,RelBase | rel: 1
27+
// LIB-NEXT: RelBase | struct/Swift | NonCopyable | s:3Lib11NonCopyableV
28+
29+
// We don't currently have a relation for Copyable.
30+
// LIB-NOT: s:s8CopyableP
31+
32+
//--- main.swift
33+
34+
import Lib
35+
36+
struct K: P & X {}
37+
// CHECK: [[@LINE-1]]:11 | protocol/Swift | P | s:3Lib1PP | Ref,RelBase | rel: 1
38+
// CHECK-NEXT: RelBase | struct/Swift | K | s:14swift_ide_test1KV
39+
// CHECK-NEXT: [[@LINE-3]]:15 | type-alias/Swift | X | s:3Lib1Xa | Ref | rel: 0
40+
// CHECK-NEXT: [[@LINE-4]]:15 | protocol/Swift | Q | s:3Lib1QP | Ref,Impl,RelBase | rel: 1
41+
// CHECK-NEXT: RelBase | struct/Swift | K | s:14swift_ide_test1KV
42+
// CHECK-NEXT: [[@LINE-6]]:15 | protocol/Swift | R | s:3Lib1RP | Ref,Impl,RelBase | rel: 1
43+
// CHECK-NEXT: RelBase | struct/Swift | K | s:14swift_ide_test1KV

0 commit comments

Comments
 (0)