Skip to content

Commit 07ebacc

Browse files
author
Nathan Hawes
committed
[Refactoring] SyntacticRename should walk into ObjC Keypath components when matching name locations.
It wasn't previously so missed them. Resolves rdar://61573935
1 parent eeab067 commit 07ebacc

File tree

10 files changed

+281
-0
lines changed

10 files changed

+281
-0
lines changed

lib/IDE/SwiftSourceDocInfo.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,36 @@ std::pair<bool, Expr*> NameMatcher::walkToExprPre(Expr *E) {
424424
return {false, nullptr};
425425
return {false, E};
426426
}
427+
case ExprKind::KeyPath: {
428+
KeyPathExpr *KP = cast<KeyPathExpr>(E);
429+
430+
// Swift keypath components are visited already, so there's no need to
431+
// handle them specially.
432+
if (!KP->isObjC())
433+
break;
434+
435+
for (auto Component: KP->getComponents()) {
436+
switch (Component.getKind()) {
437+
case KeyPathExpr::Component::Kind::UnresolvedProperty:
438+
case KeyPathExpr::Component::Kind::Property:
439+
tryResolve(ASTWalker::ParentTy(E), Component.getLoc());
440+
break;
441+
case KeyPathExpr::Component::Kind::DictionaryKey:
442+
case KeyPathExpr::Component::Kind::Invalid:
443+
break;
444+
case KeyPathExpr::Component::Kind::OptionalForce:
445+
case KeyPathExpr::Component::Kind::OptionalChain:
446+
case KeyPathExpr::Component::Kind::OptionalWrap:
447+
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
448+
case KeyPathExpr::Component::Kind::Subscript:
449+
case KeyPathExpr::Component::Kind::Identity:
450+
case KeyPathExpr::Component::Kind::TupleElement:
451+
llvm_unreachable("Unexpected component in ObjC KeyPath expression");
452+
break;
453+
}
454+
}
455+
break;
456+
}
427457
default: // ignored
428458
break;
429459
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/<base>array</base> = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/<base>array</base>)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/<base>array</base>[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/<base>dict</base> = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/<base>dict</base> . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/<base>dict</base> . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/<base>Inner</base> {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/<base>Inner</base> . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/<base>namedTuple</base> = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/<base>namedTuple</base>)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/<base>Outer</base> {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/<base>Outer</base> . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/<base>outerProp</base> = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/<base>outerProp</base>)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/<base>prop</base> = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/<base>prop</base>)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/<base>tuple</base> = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/<base>tuple</base>)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
@objcMembers class /*Outer:def*/Outer {
2+
let /*outerProp:def*/outerProp = 10
3+
4+
@objcMembers class /*Inner:def*/Inner {
5+
let /*prop:def*/prop = 20
6+
let /*tuple:def*/tuple = (1, 4)
7+
let /*namedTuple:def*/namedTuple = (x: 1, y: 3)
8+
let /*array:def*/array = [1, 2, 3]
9+
let /*dict:def*/dict = ["foo": Outer()]
10+
}
11+
}
12+
13+
// Valid
14+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*prop*/prop)
15+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array)
16+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey)
17+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*dict*/dict . someKey . /*outerProp*/outerProp)
18+
19+
// Invalid but resolved
20+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*tuple*/tuple)
21+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*namedTuple*/namedTuple)
22+
_ = #keyPath(/*Outer*/Outer . /*Inner*/Inner . /*array*/array[0] . hashValue)
23+
24+
// FIXME: Invalid and not resolved
25+
_ = #keyPath(/*Outer:unknown*/Outer . /*Inner:unknown*/Inner . /*dict:unknown*/dict . someKey . undefined)
26+
27+
// RUN: %empty-directory(%t)
28+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="Outer" -old-name "Outer" >> %t/outer.swift
29+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/outer.swift.expected %t/outer.swift
30+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="Inner" -old-name "Inner" >> %t/inner.swift
31+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/inner.swift.expected %t/inner.swift
32+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="outerProp" -old-name "outerProp" >> %t/outerprop.swift
33+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/outerprop.swift.expected %t/outerprop.swift
34+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="prop" -old-name "prop" >> %t/prop.swift
35+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/prop.swift.expected %t/prop.swift
36+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="tuple" -old-name "tuple" >> %t/tuple.swift
37+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/tuple.swift.expected %t/tuple.swift
38+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="namedTuple" -old-name "namedTuple" >> %t/namedtuple.swift
39+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/namedtuple.swift.expected %t/namedtuple.swift
40+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="array" -old-name "array" >> %t/array.swift
41+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/array.swift.expected %t/array.swift
42+
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="dict" -old-name "dict" >> %t/dict.swift
43+
// RUN: diff -u %S/FindRangeOutputs/objc-keypath/dict.swift.expected %t/dict.swift

0 commit comments

Comments
 (0)