Skip to content

Commit 6f540ab

Browse files
committed
[5.9] Fix indexing constructors with generic parameters (swiftlang#65597)
Previously in the case of a constructor like `A<Int>(value: 1)` `Fn->getLoc()` returned the location of `>(value: 1)` while the actual location we're looking for is correctly the start of `A<Int>(value: 1)`. This adjusts the location we're looking up to use the start location of the constructor instead. Fixes: swiftlang#54532 (cherry picked from commit f5fbee2 / swiftlang#65597)
1 parent 079420f commit 6f540ab

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed

lib/IDE/SourceEntityWalker.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -815,9 +815,22 @@ passReference(ValueDecl *D, Type Ty, SourceLoc BaseNameLoc, SourceRange Range,
815815

816816
if (auto *TD = dyn_cast<TypeDecl>(D)) {
817817
if (!CtorRefs.empty() && BaseNameLoc.isValid()) {
818-
Expr *Fn = CtorRefs.back()->getFn();
819-
if (Fn->getLoc() == BaseNameLoc) {
820-
D = ide::getReferencedDecl(Fn).second.getDecl();
818+
ConstructorRefCallExpr *Ctor = CtorRefs.back();
819+
SourceLoc CtorLoc = Ctor->getFn()->getLoc();
820+
// Get the location of the type, ignoring parens, rather than the start of
821+
// the Expr, to match the lookup.
822+
if (auto *TE = dyn_cast<TypeExpr>(Ctor->getBase()))
823+
CtorLoc = TE->getTypeRepr()->getWithoutParens()->getLoc();
824+
825+
bool isImplicit = false;
826+
Expr *Fn = Ctor->getFn();
827+
while (auto *ICE = dyn_cast<ImplicitConversionExpr>(Fn))
828+
Fn = ICE->getSubExpr();
829+
if (auto *DRE = dyn_cast<DeclRefExpr>(Fn))
830+
isImplicit = DRE->isImplicit();
831+
832+
if (isImplicit && CtorLoc == BaseNameLoc) {
833+
D = ide::getReferencedDecl(Ctor->getFn()).second.getDecl();
821834
if (D == nullptr) {
822835
assert(false && "Unhandled constructor reference");
823836
return true;

test/IDE/annotation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class GenCls<T> {
129129
}
130130

131131
func test2() {
132-
// CHECK: <Class@[[@LINE-19]]:7>GenCls</Class><<iStruct@>Int</iStruct>>()
132+
// CHECK: <Ctor@[[@LINE-17]]:3-Class@[[@LINE-19]]:7>GenCls</Ctor><<iStruct@>Int</iStruct>>()
133133
GenCls<Int>()
134134
}
135135

test/Index/index_generic_params.swift

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,82 @@ extension Wrapper2.NonGenericWrapped where Wrapper2Param: P1 {
8686
extension MyUnknownType where Wrapper2Param: P1 {
8787
func foo(x: Wrapper2Param) {}
8888
}
89+
90+
// MARK: - Test indexing a generic initializer
91+
92+
struct A<T> { // CHECK: [[@LINE]]:8 | struct/Swift | A | [[A_USR:.*]] | Def | rel: 0
93+
init(value: T) {} // CHECK: [[@LINE]]:3 | constructor/Swift | init(value:) | [[A_init_USR:.*]] | Def,RelChild | rel: 1
94+
}
95+
96+
// CHECK: [[@LINE+2]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
97+
// CHECK-NEXT: [[@LINE+1]]:5 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
98+
_ = A(value: 1)
99+
// CHECK: [[@LINE+2]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
100+
// CHECK-NEXT: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
101+
_ = A.init(value: 1)
102+
// CHECK: [[@LINE+3]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
103+
// CHECK-NEXT: [[@LINE+2]]:5 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
104+
// CHECK-NEXT: [[@LINE+1]]:7 | struct/Swift | Int | s:Si | Ref | rel: 0
105+
_ = A<Int>(value: 1)
106+
// CHECK: [[@LINE+3]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
107+
// CHECK-NEXT: [[@LINE+2]]:7 | struct/Swift | Int | s:Si | Ref | rel: 0
108+
// CHECK-NEXT: [[@LINE+1]]:12 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
109+
_ = A<Int>.init(value: 1)
110+
111+
// CHECK: [[@LINE+2]]:6 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
112+
// CHECK-NEXT: [[@LINE+1]]:6 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
113+
_ = (A)(value: 1)
114+
// CHECK: [[@LINE+2]]:7 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
115+
// CHECK-NEXT: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
116+
_ = ((A))(value: 1)
117+
// CHECK: [[@LINE+2]]:7 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
118+
// CHECK-NEXT: [[@LINE+1]]:11 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
119+
_ = ((A)).init(value: 1)
120+
121+
enum B { // CHECK: [[@LINE]]:6 | enum/Swift | B | [[B_USR:.*]] | Def | rel: 0
122+
struct Nested<T> { // CHECK: [[@LINE]]:10 | struct/Swift | Nested | [[B_Nested_USR:.*]] | Def,RelChild | rel: 1
123+
init(value: T) {} // CHECK: [[@LINE]]:5 | constructor/Swift | init(value:) | [[B_Nested_init_USR:.*]] | Def,RelChild | rel: 1
124+
}
125+
}
126+
127+
// CHECK: [[@LINE+3]]:5 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
128+
// CHECK: [[@LINE+2]]:7 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
129+
// CHECK: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
130+
_ = B.Nested(value: 1)
131+
// CHECK-NEXT: [[@LINE+4]]:5 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
132+
// CHECK-NEXT: [[@LINE+3]]:7 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
133+
// CHECK-NEXT: [[@LINE+2]]:7 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
134+
// CHECK-NEXT: [[@LINE+1]]:14 | struct/Swift | Int | s:Si | Ref | rel: 0
135+
_ = B.Nested<Int>(value: 1)
136+
// CHECK-NEXT: [[@LINE+4]]:5 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
137+
// CHECK-NEXT: [[@LINE+3]]:7 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
138+
// CHECK-NEXT: [[@LINE+2]]:14 | struct/Swift | Int | s:Si | Ref | rel: 0
139+
// CHECK-NEXT: [[@LINE+1]]:19 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
140+
_ = B.Nested<Int>.init(value: 1)
141+
142+
// CHECK-NEXT: [[@LINE+4]]:7 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
143+
// CHECK-NEXT: [[@LINE+3]]:9 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
144+
// CHECK-NEXT: [[@LINE+2]]:9 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
145+
// CHECK-NEXT: [[@LINE+1]]:16 | struct/Swift | Int | s:Si | Ref | rel: 0
146+
_ = ((B.Nested<Int>))(value: 1)
147+
// CHECK-NEXT: [[@LINE+4]]:7 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
148+
// CHECK-NEXT: [[@LINE+3]]:9 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
149+
// CHECK-NEXT: [[@LINE+2]]:16 | struct/Swift | Int | s:Si | Ref | rel: 0
150+
// CHECK-NEXT: [[@LINE+1]]:23 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
151+
_ = ((B.Nested<Int>)).init(value: 1)
152+
153+
enum C { // CHECK: [[@LINE]]:6 | enum/Swift | C | [[C_USR:.*]] | Def | rel: 0
154+
struct Nested { // CHECK: [[@LINE]]:10 | struct/Swift | Nested | [[C_Nested_USR:.*]] | Def,RelChild | rel: 1
155+
init(value: Int) {} // CHECK: [[@LINE]]:5 | constructor/Swift | init(value:) | [[C_Nested_init_USR:.*]] | Def,RelChild | rel: 1
156+
}
157+
}
158+
159+
// CHECK: [[@LINE+3]]:5 | enum/Swift | C | [[C_USR]] | Ref | rel: 0
160+
// CHECK-NEXT: [[@LINE+2]]:7 | struct/Swift | Nested | [[C_Nested_USR]] | Ref | rel: 0
161+
// CHECK-NEXT: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[C_Nested_init_USR]] | Ref,Call | rel: 0
162+
_ = C.Nested(value: 1)
163+
164+
// CHECK: [[@LINE+3]]:5 | enum/Swift | C | [[C_USR]] | Ref | rel: 0
165+
// CHECK-NEXT: [[@LINE+2]]:7 | struct/Swift | Nested | [[C_Nested_USR]] | Ref | rel: 0
166+
// CHECK-NEXT: [[@LINE+1]]:14 | constructor/Swift | init(value:) | [[C_Nested_init_USR]] | Ref,Call | rel: 0
167+
_ = C.Nested.init(value: 1)

0 commit comments

Comments
 (0)