mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #85741 from hamishknight/related-fix
[Index] Handle implicit reference relations for type sugar
This commit is contained in:
@@ -103,12 +103,8 @@ static bool isMemberwiseInit(swift::ValueDecl *D) {
|
||||
}
|
||||
|
||||
static SourceLoc getLocForExtension(ExtensionDecl *D) {
|
||||
// Use the 'End' token of the range, in case it is a compound name, e.g.
|
||||
// extension A.B {}
|
||||
// we want the location of 'B' token.
|
||||
if (auto *repr = D->getExtendedTypeRepr()) {
|
||||
return repr->getSourceRange().End;
|
||||
}
|
||||
if (auto *repr = D->getExtendedTypeRepr())
|
||||
return repr->getLoc();
|
||||
return SourceLoc();
|
||||
}
|
||||
|
||||
@@ -1037,12 +1033,13 @@ private:
|
||||
|
||||
bool reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isImplicit, SymbolRoleSet Relations, Decl *Related);
|
||||
|
||||
/// Report a related type relation for a given TypeRepr.
|
||||
/// Report a related type relation for a given TypeLoc. Don't call this
|
||||
/// directly, use \c reportRelatedTypeRef instead.
|
||||
///
|
||||
/// NOTE: If the dependent type is a typealias, report the underlying types as
|
||||
/// well.
|
||||
///
|
||||
/// \param TR The type being referenced.
|
||||
/// \param TL The type being referenced.
|
||||
/// \param Relations The relationship between the referenced type and the
|
||||
/// passed Decl.
|
||||
/// \param Related The Decl that is referencing the type.
|
||||
@@ -1050,8 +1047,9 @@ private:
|
||||
/// typealias' underlying type.
|
||||
/// \param ParentLoc The parent location of the reference that should be used
|
||||
/// for implicit references.
|
||||
bool reportRelatedTypeRepr(const TypeRepr *TR, SymbolRoleSet Relations,
|
||||
Decl *Related, bool Implicit, SourceLoc ParentLoc);
|
||||
bool reportRelatedTypeRefImpl(const TypeLoc &TL, SymbolRoleSet Relations,
|
||||
Decl *Related, bool Implicit,
|
||||
SourceLoc ParentLoc);
|
||||
|
||||
/// Report a related type relation for a Type at a given location.
|
||||
///
|
||||
@@ -1531,66 +1529,85 @@ bool IndexSwiftASTWalker::reportInheritedTypeRefs(InheritedTypes Inherited,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IndexSwiftASTWalker::reportRelatedTypeRepr(const TypeRepr *TR,
|
||||
SymbolRoleSet Relations,
|
||||
Decl *Related, bool Implicit,
|
||||
SourceLoc ParentLoc) {
|
||||
// Look through parens/specifiers/attributes.
|
||||
while (true) {
|
||||
if (TR->isParenType()) {
|
||||
TR = TR->getWithoutParens();
|
||||
continue;
|
||||
}
|
||||
if (auto *SPR = dyn_cast<SpecifierTypeRepr>(TR)) {
|
||||
TR = SPR->getBase();
|
||||
continue;
|
||||
}
|
||||
if (auto *ATR = dyn_cast<AttributedTypeRepr>(TR)) {
|
||||
TR = ATR->getTypeRepr();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// NOTE: We don't yet handle InverseTypeRepr since we don't have an inverse
|
||||
// relation for inheritance.
|
||||
|
||||
if (auto *composite = dyn_cast<CompositionTypeRepr>(TR)) {
|
||||
for (auto *Type : composite->getTypes()) {
|
||||
if (!reportRelatedTypeRepr(Type, Relations, Related, Implicit,
|
||||
ParentLoc)) {
|
||||
return false;
|
||||
bool IndexSwiftASTWalker::reportRelatedTypeRefImpl(const TypeLoc &TL,
|
||||
SymbolRoleSet Relations,
|
||||
Decl *Related, bool Implicit,
|
||||
SourceLoc ParentLoc) {
|
||||
auto *TR = TL.getTypeRepr();
|
||||
if (TR) {
|
||||
// Look through parens/specifiers/attributes.
|
||||
while (true) {
|
||||
if (TR->isParenType()) {
|
||||
TR = TR->getWithoutParens();
|
||||
continue;
|
||||
}
|
||||
if (auto *SPR = dyn_cast<SpecifierTypeRepr>(TR)) {
|
||||
TR = SPR->getBase();
|
||||
continue;
|
||||
}
|
||||
if (auto *ATR = dyn_cast<AttributedTypeRepr>(TR)) {
|
||||
TR = ATR->getTypeRepr();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// NOTE: We don't yet handle InverseTypeRepr since we don't have an inverse
|
||||
// relation for inheritance.
|
||||
|
||||
if (auto *composite = dyn_cast<CompositionTypeRepr>(TR)) {
|
||||
for (auto *Type : composite->getTypes()) {
|
||||
// Note this doesn't handle type sugar cases where the decl is only
|
||||
// available on the semantic type. This isn't currently something that
|
||||
// happens for type compositions though.
|
||||
if (!reportRelatedTypeRefImpl(Type, Relations, Related, Implicit,
|
||||
ParentLoc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
auto *declRefTR = dyn_cast<DeclRefTypeRepr>(TR);
|
||||
if (!declRefTR)
|
||||
return true;
|
||||
SourceLoc Loc = [&]() {
|
||||
if (ParentLoc)
|
||||
return ParentLoc;
|
||||
if (TR)
|
||||
return TR->getLoc();
|
||||
return SourceLoc();
|
||||
}();
|
||||
|
||||
auto *declRefTR = dyn_cast_or_null<DeclRefTypeRepr>(TR);
|
||||
if (!declRefTR) {
|
||||
if (!TL.getType())
|
||||
return true;
|
||||
|
||||
// If we don't have a TypeRepr, we're e.g indexing a Swift module, so want
|
||||
// to look at the Type instead. If we have a TypeRepr but have no explicit
|
||||
// decl reference, fall back to indexing an implicit reference to handle
|
||||
// type sugar e.g Array for `[Int]`.
|
||||
return reportRelatedType(TL.getType(), Relations, Related,
|
||||
Implicit || TR, Loc);
|
||||
}
|
||||
|
||||
auto *VD = declRefTR->getBoundDecl();
|
||||
if (!VD)
|
||||
return true;
|
||||
|
||||
SourceLoc IdLoc = ParentLoc.isValid() ? ParentLoc : declRefTR->getLoc();
|
||||
if (auto *TAD = dyn_cast<TypeAliasDecl>(VD)) {
|
||||
IndexSymbol Info;
|
||||
if (Implicit)
|
||||
Info.roles |= (unsigned)SymbolRole::Implicit;
|
||||
if (!reportRef(TAD, IdLoc, Info, std::nullopt))
|
||||
if (!reportRef(TAD, Loc, Info, std::nullopt))
|
||||
return false;
|
||||
|
||||
// Recurse into the underlying type and report any found references as
|
||||
// implicit references at the location of the typealias reference.
|
||||
if (auto *UTR = TAD->getUnderlyingTypeRepr()) {
|
||||
return reportRelatedTypeRepr(UTR, Relations, Related,
|
||||
/*Implicit*/ true, /*ParentLoc*/ IdLoc);
|
||||
}
|
||||
// If we don't have a TypeRepr available, this is a typealias in another
|
||||
// module, consult the computed underlying type.
|
||||
return reportRelatedType(TAD->getUnderlyingType(), Relations, Related,
|
||||
/*Implicit*/ true, /*ParentLoc*/ IdLoc);
|
||||
TypeLoc UnderlyingTL(TAD->getUnderlyingTypeRepr(),
|
||||
TAD->getUnderlyingType());
|
||||
return reportRelatedTypeRefImpl(UnderlyingTL, Relations, Related,
|
||||
/*Implicit*/ true, /*ParentLoc*/ Loc);
|
||||
}
|
||||
if (auto *NTD = dyn_cast<NominalTypeDecl>(VD)) {
|
||||
if (!reportRelatedRef(NTD, IdLoc, Implicit, Relations, Related))
|
||||
if (!reportRelatedRef(NTD, Loc, Implicit, Relations, Related))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1618,19 +1635,8 @@ bool IndexSwiftASTWalker::reportRelatedType(Type Ty, SymbolRoleSet Relations,
|
||||
bool IndexSwiftASTWalker::reportRelatedTypeRef(const TypeLoc &TL,
|
||||
SymbolRoleSet Relations,
|
||||
Decl *Related) {
|
||||
// If we have a TypeRepr, prefer that since it lets us match up source
|
||||
// locations with the code the user wrote.
|
||||
if (auto *TR = TL.getTypeRepr()) {
|
||||
return reportRelatedTypeRepr(TR, Relations, Related, /*Implicit*/ false,
|
||||
/*ParentLoc*/ SourceLoc());
|
||||
}
|
||||
// Otherwise fall back to reporting the Type, this is necessary when indexing
|
||||
// swiftmodules.
|
||||
if (auto Ty = TL.getType()) {
|
||||
return reportRelatedType(Ty, Relations, Related,
|
||||
/*Implicit*/ false, SourceLoc());
|
||||
}
|
||||
return true;
|
||||
return reportRelatedTypeRefImpl(TL, Relations, Related, /*Implicit*/ false,
|
||||
/*ParentLoc*/ SourceLoc());
|
||||
}
|
||||
|
||||
bool IndexSwiftASTWalker::reportPseudoAccessor(AbstractStorageDecl *D,
|
||||
|
||||
@@ -29,6 +29,48 @@ public struct NonCopyable: NonCopyableProto & ~Copyable {}
|
||||
// We don't currently have a relation for Copyable.
|
||||
// LIB-NOT: s:s8CopyableP
|
||||
|
||||
extension [Int] {
|
||||
public func foo() {}
|
||||
}
|
||||
// LIB: 0:0 | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE3fooyyF | Def | rel: 0
|
||||
// LIB-NEXT: 0:0 | struct/Swift | Array | s:Sa | Ref,RelExt | rel: 1
|
||||
// LIB-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE3fooyyF
|
||||
|
||||
extension Array where Element == Int {
|
||||
public func bar() {}
|
||||
}
|
||||
// LIB: 0:0 | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE3baryyF | Def | rel: 0
|
||||
// LIB-NEXT: 0:0 | struct/Swift | Array | s:Sa | Ref,RelExt | rel: 1
|
||||
// LIB-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE3baryyF
|
||||
|
||||
extension Int? {
|
||||
public func baz() {}
|
||||
}
|
||||
// LIB: 0:0 | extension/ext-enum/Swift | Optional | s:e:s:Sq3LibSiRszlE3bazyyF | Def | rel: 0
|
||||
// LIB-NEXT: 0:0 | enum/Swift | Optional | s:Sq | Ref,RelExt | rel: 1
|
||||
// LIB-NEXT: RelExt | extension/ext-enum/Swift | Optional | s:e:s:Sq3LibSiRszlE3bazyyF
|
||||
|
||||
public typealias IntArray = [Int]
|
||||
public typealias ArrayOf<T> = [T]
|
||||
|
||||
extension IntArray {
|
||||
public func qux() {}
|
||||
}
|
||||
// We don't currently report references to typealiases in imported modules, so
|
||||
// this is just an extension of Array.
|
||||
// LIB: 0:0 | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE3quxyyF | Def | rel: 0
|
||||
// LIB-NEXT: 0:0 | struct/Swift | Array | s:Sa | Ref,RelExt | rel: 1
|
||||
// LIB-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE3quxyyF
|
||||
|
||||
extension ArrayOf<Int> {
|
||||
public func flim() {}
|
||||
}
|
||||
// We don't currently report references to typealiases in imported modules, so
|
||||
// this is just an extension of Array.
|
||||
// LIB: 0:0 | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE4flimyyF | Def | rel: 0
|
||||
// LIB-NEXT: 0:0 | struct/Swift | Array | s:Sa | Ref,RelExt | rel: 1
|
||||
// LIB-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa3LibSiRszlE4flimyyF
|
||||
|
||||
//--- main.swift
|
||||
|
||||
import Lib
|
||||
@@ -41,3 +83,19 @@ struct K: P & X {}
|
||||
// CHECK-NEXT: RelBase | struct/Swift | K | s:14swift_ide_test1KV
|
||||
// CHECK-NEXT: [[@LINE-6]]:15 | protocol/Swift | R | s:3Lib1RP | Ref,Impl,RelBase | rel: 1
|
||||
// CHECK-NEXT: RelBase | struct/Swift | K | s:14swift_ide_test1KV
|
||||
|
||||
extension IntArray {
|
||||
// CHECK: [[@LINE-1]]:11 | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4flamyyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:11 | type-alias/Swift | IntArray | s:3Lib8IntArraya | Ref | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-3]]:11 | struct/Swift | Array | s:Sa | Ref,Impl,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4flamyyF
|
||||
func flam() {}
|
||||
}
|
||||
|
||||
extension ArrayOf<Int> {
|
||||
// CHECK: [[@LINE-1]]:11 | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4bishyyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:11 | type-alias/Swift | ArrayOf | s:3Lib7ArrayOfa | Ref | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-3]]:11 | struct/Swift | Array | s:Sa | Ref,Impl,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4bishyyF
|
||||
func bish() {}
|
||||
}
|
||||
|
||||
@@ -564,3 +564,48 @@ class Subclass: BaseClass {
|
||||
// CHECK-NEXT: RelChild,RelAcc | instance-property/Swift | x | s:14swift_ide_test8SubclassC1xSivp
|
||||
}
|
||||
}
|
||||
|
||||
extension [Int] {
|
||||
// CHECK: [[@LINE-1]]:11 | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE3fooyyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:11 | struct/Swift | Array | s:Sa | Ref,Impl,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE3fooyyF
|
||||
// CHECK-NEXT: [[@LINE-4]]:12 | struct/Swift | Int | s:Si | Ref | rel: 0
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
extension Array where Element == Int {
|
||||
// CHECK: [[@LINE-1]]:11 | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE3baryyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:11 | struct/Swift | Array | s:Sa | Ref,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE3baryyF
|
||||
// CHECK-NEXT: [[@LINE-4]]:23 | type-alias/generic-type-param/Swift | Element | s:Sa7Elementxmfp | Ref | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-5]]:34 | struct/Swift | Int | s:Si | Ref | rel: 0
|
||||
func bar() {}
|
||||
}
|
||||
|
||||
extension Int? {
|
||||
// CHECK: [[@LINE-1]]:14 | extension/ext-enum/Swift | Optional | s:e:s:Sq14swift_ide_testSiRszlE3bazyyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:14 | enum/Swift | Optional | s:Sq | Ref,Impl,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-enum/Swift | Optional | s:e:s:Sq14swift_ide_testSiRszlE3bazyyF
|
||||
// CHECK-NEXT: [[@LINE-4]]:11 | struct/Swift | Int | s:Si | Ref | rel: 0
|
||||
func baz() {}
|
||||
}
|
||||
|
||||
typealias IntArray = [Int]
|
||||
typealias ArrayOf<T> = [T]
|
||||
|
||||
extension IntArray {
|
||||
// CHECK: [[@LINE-1]]:11 | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4flamyyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:11 | type-alias/Swift | IntArray | s:14swift_ide_test8IntArraya | Ref | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-3]]:11 | struct/Swift | Array | s:Sa | Ref,Impl,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4flamyyF
|
||||
func flam() {}
|
||||
}
|
||||
|
||||
extension ArrayOf<Int> {
|
||||
// CHECK: [[@LINE-1]]:11 | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4bishyyF | Def | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-2]]:11 | type-alias/Swift | ArrayOf | s:14swift_ide_test7ArrayOfa | Ref | rel: 0
|
||||
// CHECK-NEXT: [[@LINE-3]]:11 | struct/Swift | Array | s:Sa | Ref,Impl,RelExt | rel: 1
|
||||
// CHECK-NEXT: RelExt | extension/ext-struct/Swift | Array | s:e:s:Sa14swift_ide_testSiRszlE4bishyyF
|
||||
func bish() {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user