Skip to content

Commit a535203

Browse files
committed
[Refactoring] Only rename variables in capture lists once
Inside capture lists like `{ [test] in }`, `test` refers to both the newly declared, captured variable and the referenced variable it is initialized from. We currently try to rename it twice, yielding invalid, confusing results. Make sure to only record this situation once. Fixes rdar://78522816 [SR-14661]
1 parent c3e9676 commit a535203

13 files changed

+163
-1
lines changed

lib/IDE/Refactoring.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,22 @@ class RenameRangeCollector : public IndexDataConsumer {
654654
Action startSourceEntity(const IndexSymbol &symbol) override {
655655
if (symbol.USR == USR) {
656656
if (auto loc = indexSymbolToRenameLoc(symbol, newName)) {
657-
locations.push_back(std::move(*loc));
657+
// Inside capture lists like `{ [test] in }`, 'test' refers to both the
658+
// newly declared, captured variable and the referenced variable it is
659+
// initialized from. Make sure to only rename it once.
660+
auto existingLoc = llvm::find_if(locations, [&](RenameLoc searchLoc) {
661+
return searchLoc.Line == loc->Line && searchLoc.Column == loc->Column;
662+
});
663+
if (existingLoc == locations.end()) {
664+
locations.push_back(std::move(*loc));
665+
} else {
666+
assert(existingLoc->OldName == loc->OldName &&
667+
existingLoc->NewName == loc->NewName &&
668+
existingLoc->IsFunctionLike == loc->IsFunctionLike &&
669+
existingLoc->IsNonProtocolType ==
670+
existingLoc->IsNonProtocolType &&
671+
"Asked to do a different rename for the same location?");
672+
}
658673
}
659674
}
660675
return IndexDataConsumer::Continue;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
func test1() {
2+
if true {
3+
let x = 1
4+
print(x)
5+
} else {
6+
let x = 2
7+
print(x)
8+
}
9+
}
10+
11+
func test2(arg1: Int?, arg2: (Int, String)?) {
12+
if let x = arg1 {
13+
print(x)
14+
} else if let (x, y) = arg2 {
15+
print(x, y)
16+
}
17+
}
18+
19+
func test3(arg: Int?) {
20+
switch arg {
21+
case let .some(x) where x == 0:
22+
print(x)
23+
case let .some(x) where x == 1,
24+
let .some(x) where x == 2:
25+
print(x)
26+
fallthrough
27+
case let .some(x) where x == 3:
28+
print(x)
29+
default:
30+
break
31+
}
32+
}
33+
34+
struct Err1 : Error { }
35+
func test4(arg: () throws -> Void) {
36+
do {
37+
try arg()
38+
} catch let x as Err1 {
39+
print(x)
40+
} catch let x {
41+
print(x)
42+
}
43+
}
44+
45+
func test5(_ x: Int) {
46+
let x = x
47+
print(x)
48+
}
49+
50+
func testCaputreVariable() {
51+
let capturedVariableRenamed = 0
52+
53+
_ = { [capturedVariableRenamed] in
54+
print(capturedVariableRenamed)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/casebind_1.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/casebind_2.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/catch_1.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/catch_2.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/ifbind_1.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/ifbind_2.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/localvar_1.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

test/refactoring/rename/Outputs/local/localvar_2.swift.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ func test5(_ x: Int) {
4747
print(x)
4848
}
4949

50+
func testCaputreVariable() {
51+
let capturedVariable = 0
52+
53+
_ = { [capturedVariable] in
54+
print(capturedVariable)
55+
}
56+
}
57+

0 commit comments

Comments
 (0)