Fix indexing constructors with generic parameters (#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: https://github.com/apple/swift/issues/54532
This commit is contained in:
Keith Smiley
2023-05-05 15:20:07 -07:00
committed by GitHub
parent 1566eccbad
commit f5fbee2f26
3 changed files with 96 additions and 4 deletions

View File

@@ -827,9 +827,22 @@ passReference(ValueDecl *D, Type Ty, SourceLoc BaseNameLoc, SourceRange Range,
if (auto *TD = dyn_cast<TypeDecl>(D)) {
if (!CtorRefs.empty() && BaseNameLoc.isValid()) {
Expr *Fn = CtorRefs.back()->getFn();
if (Fn->getLoc() == BaseNameLoc) {
D = ide::getReferencedDecl(Fn).second.getDecl();
ConstructorRefCallExpr *Ctor = CtorRefs.back();
SourceLoc CtorLoc = Ctor->getFn()->getLoc();
// Get the location of the type, ignoring parens, rather than the start of
// the Expr, to match the lookup.
if (auto *TE = dyn_cast<TypeExpr>(Ctor->getBase()))
CtorLoc = TE->getTypeRepr()->getWithoutParens()->getLoc();
bool isImplicit = false;
Expr *Fn = Ctor->getFn();
while (auto *ICE = dyn_cast<ImplicitConversionExpr>(Fn))
Fn = ICE->getSubExpr();
if (auto *DRE = dyn_cast<DeclRefExpr>(Fn))
isImplicit = DRE->isImplicit();
if (isImplicit && CtorLoc == BaseNameLoc) {
D = ide::getReferencedDecl(Ctor->getFn()).second.getDecl();
if (D == nullptr) {
assert(false && "Unhandled constructor reference");
return true;

View File

@@ -129,7 +129,7 @@ class GenCls<T> {
}
func test2() {
// CHECK: <Class@[[@LINE-19]]:7>GenCls</Class><<iStruct@>Int</iStruct>>()
// CHECK: <Ctor@[[@LINE-17]]:3-Class@[[@LINE-19]]:7>GenCls</Ctor><<iStruct@>Int</iStruct>>()
GenCls<Int>()
}

View File

@@ -86,3 +86,82 @@ extension Wrapper2.NonGenericWrapped where Wrapper2Param: P1 {
extension MyUnknownType where Wrapper2Param: P1 {
func foo(x: Wrapper2Param) {}
}
// MARK: - Test indexing a generic initializer
struct A<T> { // CHECK: [[@LINE]]:8 | struct/Swift | A | [[A_USR:.*]] | Def | rel: 0
init(value: T) {} // CHECK: [[@LINE]]:3 | constructor/Swift | init(value:) | [[A_init_USR:.*]] | Def,RelChild | rel: 1
}
// CHECK: [[@LINE+2]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:5 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
_ = A(value: 1)
// CHECK: [[@LINE+2]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
_ = A.init(value: 1)
// CHECK: [[@LINE+3]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:5 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
// CHECK-NEXT: [[@LINE+1]]:7 | struct/Swift | Int | s:Si | Ref | rel: 0
_ = A<Int>(value: 1)
// CHECK: [[@LINE+3]]:5 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:7 | struct/Swift | Int | s:Si | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:12 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
_ = A<Int>.init(value: 1)
// CHECK: [[@LINE+2]]:6 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:6 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
_ = (A)(value: 1)
// CHECK: [[@LINE+2]]:7 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
_ = ((A))(value: 1)
// CHECK: [[@LINE+2]]:7 | struct/Swift | A | [[A_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:11 | constructor/Swift | init(value:) | [[A_init_USR]] | Ref,Call | rel: 0
_ = ((A)).init(value: 1)
enum B { // CHECK: [[@LINE]]:6 | enum/Swift | B | [[B_USR:.*]] | Def | rel: 0
struct Nested<T> { // CHECK: [[@LINE]]:10 | struct/Swift | Nested | [[B_Nested_USR:.*]] | Def,RelChild | rel: 1
init(value: T) {} // CHECK: [[@LINE]]:5 | constructor/Swift | init(value:) | [[B_Nested_init_USR:.*]] | Def,RelChild | rel: 1
}
}
// CHECK: [[@LINE+3]]:5 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
// CHECK: [[@LINE+2]]:7 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
// CHECK: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
_ = B.Nested(value: 1)
// CHECK-NEXT: [[@LINE+4]]:5 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+3]]:7 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:7 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
// CHECK-NEXT: [[@LINE+1]]:14 | struct/Swift | Int | s:Si | Ref | rel: 0
_ = B.Nested<Int>(value: 1)
// CHECK-NEXT: [[@LINE+4]]:5 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+3]]:7 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:14 | struct/Swift | Int | s:Si | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:19 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
_ = B.Nested<Int>.init(value: 1)
// CHECK-NEXT: [[@LINE+4]]:7 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+3]]:9 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:9 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
// CHECK-NEXT: [[@LINE+1]]:16 | struct/Swift | Int | s:Si | Ref | rel: 0
_ = ((B.Nested<Int>))(value: 1)
// CHECK-NEXT: [[@LINE+4]]:7 | enum/Swift | B | [[B_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+3]]:9 | struct/Swift | Nested | [[B_Nested_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:16 | struct/Swift | Int | s:Si | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:23 | constructor/Swift | init(value:) | [[B_Nested_init_USR]] | Ref,Call | rel: 0
_ = ((B.Nested<Int>)).init(value: 1)
enum C { // CHECK: [[@LINE]]:6 | enum/Swift | C | [[C_USR:.*]] | Def | rel: 0
struct Nested { // CHECK: [[@LINE]]:10 | struct/Swift | Nested | [[C_Nested_USR:.*]] | Def,RelChild | rel: 1
init(value: Int) {} // CHECK: [[@LINE]]:5 | constructor/Swift | init(value:) | [[C_Nested_init_USR:.*]] | Def,RelChild | rel: 1
}
}
// CHECK: [[@LINE+3]]:5 | enum/Swift | C | [[C_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:7 | struct/Swift | Nested | [[C_Nested_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:7 | constructor/Swift | init(value:) | [[C_Nested_init_USR]] | Ref,Call | rel: 0
_ = C.Nested(value: 1)
// CHECK: [[@LINE+3]]:5 | enum/Swift | C | [[C_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+2]]:7 | struct/Swift | Nested | [[C_Nested_USR]] | Ref | rel: 0
// CHECK-NEXT: [[@LINE+1]]:14 | constructor/Swift | init(value:) | [[C_Nested_init_USR]] | Ref,Call | rel: 0
_ = C.Nested.init(value: 1)