mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Refactoring][Migrator] Fix rename of callsites with a trailing closure argument
A label range of 0 length was being reported as the label of trailing closure
arguments, just before the opening '{'.
For the rename refactoring, this meant that if the corresponding parameter had
an external label (e.g. 'a') the occurrence would be treated as not matching the
expected symbol name, and so not be updated at all.
For the migrator, when renaming a function with an unlabelled closure for its
last parameter to have a label, it would incorrectly insert the new label in
front of the opening '{' on all of that function's callsites with trailing
closures.
Resolves rdar://problem/42162571
This commit is contained in:
@@ -598,6 +598,7 @@ enum class LabelRangeEndAt: int8_t {
|
||||
struct CallArgInfo {
|
||||
Expr *ArgExp;
|
||||
CharSourceRange LabelRange;
|
||||
bool IsTrailingClosure;
|
||||
CharSourceRange getEntireCharRange(const SourceManager &SM) const;
|
||||
};
|
||||
|
||||
@@ -605,6 +606,8 @@ std::vector<CallArgInfo>
|
||||
getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind);
|
||||
|
||||
// Get the ranges of argument labels from an Arg, either tuple or paren.
|
||||
// This includes empty ranges for any unlabelled arguments, and excludes
|
||||
// trailing closures.
|
||||
std::vector<CharSourceRange>
|
||||
getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind);
|
||||
|
||||
|
||||
@@ -1640,15 +1640,18 @@ getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) {
|
||||
if (EndKind == LabelRangeEndAt::LabelNameOnly)
|
||||
LabelEnd = LabelStart.getAdvancedLoc(NameIdentifier.getLength());
|
||||
}
|
||||
|
||||
bool IsTrailingClosure = TE->hasTrailingClosure() &&
|
||||
ElemIndex == TE->getNumElements() - 1;
|
||||
InfoVec.push_back({getSingleNonImplicitChild(Elem),
|
||||
CharSourceRange(SM, LabelStart, LabelEnd)});
|
||||
CharSourceRange(SM, LabelStart, LabelEnd), IsTrailingClosure});
|
||||
++ElemIndex;
|
||||
}
|
||||
} else if (auto *PE = dyn_cast<ParenExpr>(Arg)) {
|
||||
if (auto Sub = PE->getSubExpr())
|
||||
InfoVec.push_back({getSingleNonImplicitChild(Sub),
|
||||
CharSourceRange(Sub->getStartLoc(), 0)});
|
||||
CharSourceRange(Sub->getStartLoc(), 0),
|
||||
PE->hasTrailingClosure()
|
||||
});
|
||||
}
|
||||
return InfoVec;
|
||||
}
|
||||
@@ -1657,7 +1660,13 @@ std::vector<CharSourceRange> swift::ide::
|
||||
getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) {
|
||||
std::vector<CharSourceRange> Ranges;
|
||||
auto InfoVec = getCallArgInfo(SM, Arg, EndKind);
|
||||
std::transform(InfoVec.begin(), InfoVec.end(), std::back_inserter(Ranges),
|
||||
|
||||
auto EndWithoutTrailing = std::remove_if(InfoVec.begin(), InfoVec.end(),
|
||||
[](CallArgInfo &Info) {
|
||||
return Info.IsTrailingClosure;
|
||||
});
|
||||
std::transform(InfoVec.begin(), EndWithoutTrailing,
|
||||
std::back_inserter(Ranges),
|
||||
[](CallArgInfo &Info) { return Info.LabelRange; });
|
||||
return Ranges;
|
||||
}
|
||||
|
||||
@@ -529,6 +529,17 @@
|
||||
"RightComment": "Int",
|
||||
"ModuleName": "Cities"
|
||||
},
|
||||
{
|
||||
"DiffItemKind": "CommonDiffItem",
|
||||
"NodeKind": "Function",
|
||||
"NodeAnnotation": "Rename",
|
||||
"ChildIndex": "0",
|
||||
"LeftUsr": "s:6Cities12ToplevelTypeC8trailingyyySayypGSgcF",
|
||||
"LeftComment": "",
|
||||
"RightUsr": "",
|
||||
"RightComment": "trailing2(a:)",
|
||||
"ModuleName": "Cities"
|
||||
},
|
||||
{
|
||||
"DiffItemKind": "CommonDiffItem",
|
||||
"NodeKind": "TypeDecl",
|
||||
|
||||
@@ -62,6 +62,7 @@ open class ToplevelType {
|
||||
public init() {}
|
||||
public init(recordName: String) {}
|
||||
open func member(_ x: @escaping ([Any]?) -> Void) {}
|
||||
open func trailing(_ x: @escaping ([Any]?) -> Void) {}
|
||||
}
|
||||
|
||||
public var GlobalAttribute: String = ""
|
||||
|
||||
@@ -22,3 +22,7 @@ class MySubTopLevelType2: ToplevelType {
|
||||
class SubCities: Cities {
|
||||
override var yogurt: Int { return 2 }
|
||||
}
|
||||
|
||||
func boo(_ a: ToplevelType) {
|
||||
a.trailing { print($0!) }
|
||||
}
|
||||
|
||||
@@ -22,3 +22,7 @@ class MySubTopLevelType2: ToplevelType {
|
||||
class SubCities: Cities {
|
||||
override var cheese: Int { return 2 }
|
||||
}
|
||||
|
||||
func boo(_ a: ToplevelType) {
|
||||
a.trailing2 { print($0!) }
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/<base>withTrailingClosure</base>(<arglabel index=0>x</argla
|
||||
/*trailing:call*/<base>withTrailingClosure</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
func /*defaults:def*/withDefaults(_ xx: Int = 4, y: Int = 2, x: Int = 1) {}
|
||||
|
||||
// valid
|
||||
/*defaults:call*/withDefaults()
|
||||
/*defaults:call*/withDefaults(2)
|
||||
/*defaults:call*/withDefaults(y: 2)
|
||||
/*defaults:call*/withDefaults(2, x: 3)
|
||||
/*defaults:call*/withDefaults(y: 2, x: 3)
|
||||
/*defaults:call*/withDefaults(2, y: 1, x: 4)
|
||||
|
||||
// false positives
|
||||
/*defaults:call*/withDefaults(y: 2, 3)
|
||||
/*defaults:call*/withDefaults(y: 2, 4, x: 3)
|
||||
|
||||
// invalid
|
||||
/*defaults:call*/withDefaults(x: 2, y: 3)
|
||||
|
||||
|
||||
func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
|
||||
// valid
|
||||
/*trailing:call*/withTrailingClosure(x: 2, y: { return 1})
|
||||
/*trailing:call*/withTrailingClosure(x: 2) { return 1}
|
||||
|
||||
// false positives
|
||||
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
|
||||
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/<base>trailingOnly</base>(<arglabel index=0>a</arglabel><param index=0></param>: () -> ()) {}
|
||||
/*trailing-only:call*/<base>trailingOnly</base>(<callarg index=0>a</callarg><callcolon index=0>: </callcolon>{})
|
||||
/*trailing-only:call*/<base>trailingOnly</base> {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
// valid
|
||||
/*varargs:call*/withVarargs(x: 1, 2, 3, y: 2, 4)
|
||||
/*varargs:call*/withVarargs(y: 2, 4)
|
||||
|
||||
// false positives
|
||||
/*varargs:call*/withVarargs(x: 1, y: 2, 4, 5)
|
||||
|
||||
//invalid
|
||||
/*varargs:call*/withVarargs(2, y: 2)
|
||||
|
||||
|
||||
func /*varargs2:def*/withVarargs(x: Int, y: Int, _: Int...) {}
|
||||
|
||||
// valid
|
||||
/*varargs2:call*/withVarargs(x: 1, y: 2, 4, 5)
|
||||
/*varargs2:call*/withVarargs(x: 1, y: 2)
|
||||
|
||||
// false positive
|
||||
/*varargs2:call*/withVarargs(x: 1, 2, y: 2, 4)
|
||||
|
||||
|
||||
func /*mixed:def*/withAllOfTheAbove(x: Int = 2, _: Int..., z: Int = 2, c: () -> Int) {}
|
||||
|
||||
// valid
|
||||
/*mixed:call*/withAllOfTheAbove(2){ return 1 }
|
||||
/*mixed:call*/withAllOfTheAbove(x: 1, 2, c: {return 1})
|
||||
/*mixed:call*/withAllOfTheAbove(x: 1, c: {return 1})
|
||||
/*mixed:call*/withAllOfTheAbove(1, z: 1) { return 1 }
|
||||
/*mixed:call*/withAllOfTheAbove(1, 2, c: {return 1})
|
||||
|
||||
// false positives
|
||||
/*mixed:call*/withAllOfTheAbove(z: 1, 2, c: {return 1})
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/betterName(a: Int, b: () -> Int) {}
|
||||
/*trailing:call*/betterName(a: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
func /*defaults:def*/withDefaults(_ xx: Int = 4, y: Int = 2, x: Int = 1) {}
|
||||
|
||||
// valid
|
||||
/*defaults:call*/withDefaults()
|
||||
/*defaults:call*/withDefaults(2)
|
||||
/*defaults:call*/withDefaults(y: 2)
|
||||
/*defaults:call*/withDefaults(2, x: 3)
|
||||
/*defaults:call*/withDefaults(y: 2, x: 3)
|
||||
/*defaults:call*/withDefaults(2, y: 1, x: 4)
|
||||
|
||||
// false positives
|
||||
/*defaults:call*/withDefaults(y: 2, 3)
|
||||
/*defaults:call*/withDefaults(y: 2, 4, x: 3)
|
||||
|
||||
// invalid
|
||||
/*defaults:call*/withDefaults(x: 2, y: 3)
|
||||
|
||||
|
||||
func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
|
||||
// valid
|
||||
/*trailing:call*/withTrailingClosure(x: 2, y: { return 1})
|
||||
/*trailing:call*/withTrailingClosure(x: 2) { return 1}
|
||||
|
||||
// false positives
|
||||
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
|
||||
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/betterName(b: () -> ()) {}
|
||||
/*trailing-only:call*/betterName(b: {})
|
||||
/*trailing-only:call*/betterName {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
// valid
|
||||
/*varargs:call*/withVarargs(x: 1, 2, 3, y: 2, 4)
|
||||
/*varargs:call*/withVarargs(y: 2, 4)
|
||||
|
||||
// false positives
|
||||
/*varargs:call*/withVarargs(x: 1, y: 2, 4, 5)
|
||||
|
||||
//invalid
|
||||
/*varargs:call*/withVarargs(2, y: 2)
|
||||
|
||||
|
||||
func /*varargs2:def*/withVarargs(x: Int, y: Int, _: Int...) {}
|
||||
|
||||
// valid
|
||||
/*varargs2:call*/withVarargs(x: 1, y: 2, 4, 5)
|
||||
/*varargs2:call*/withVarargs(x: 1, y: 2)
|
||||
|
||||
// false positive
|
||||
/*varargs2:call*/withVarargs(x: 1, 2, y: 2, 4)
|
||||
|
||||
|
||||
func /*mixed:def*/withAllOfTheAbove(x: Int = 2, _: Int..., z: Int = 2, c: () -> Int) {}
|
||||
|
||||
// valid
|
||||
/*mixed:call*/withAllOfTheAbove(2){ return 1 }
|
||||
/*mixed:call*/withAllOfTheAbove(x: 1, 2, c: {return 1})
|
||||
/*mixed:call*/withAllOfTheAbove(x: 1, c: {return 1})
|
||||
/*mixed:call*/withAllOfTheAbove(1, z: 1) { return 1 }
|
||||
/*mixed:call*/withAllOfTheAbove(1, 2, c: {return 1})
|
||||
|
||||
// false positives
|
||||
/*mixed:call*/withAllOfTheAbove(z: 1, 2, c: {return 1})
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/betterName(a: Int..., b: Int, c: Int) {}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ func /*trailing:def*/withTrailingClosure(x: Int, y: () -> Int) {}
|
||||
/*trailing:call*/withTrailingClosure(x: 2)
|
||||
{ return 1}
|
||||
|
||||
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
|
||||
/*trailing-only:call*/trailingOnly(a: {})
|
||||
/*trailing-only:call*/trailingOnly {}
|
||||
|
||||
|
||||
func /*varargs:def*/withVarargs(x: Int..., y: Int, _: Int) {}
|
||||
|
||||
@@ -69,6 +73,8 @@ func /*mixed:def*/withAllOfTheAbove(x: Int = 2, _: Int..., z: Int = 2, c: () ->
|
||||
// RUN: diff -u %S/Outputs/callsites/defaults.swift.expected %t.result/callsites_defaults.swift
|
||||
// RUN: %refactor -syntactic-rename -source-filename %s -pos="trailing" -is-function-like -old-name "withTrailingClosure(x:y:)" -new-name "betterName(a:b:)" >> %t.result/callsites_trailing.swift
|
||||
// RUN: diff -u %S/Outputs/callsites/trailing.swift.expected %t.result/callsites_trailing.swift
|
||||
// RUN: %refactor -syntactic-rename -source-filename %s -pos="trailing-only" -is-function-like -old-name "trailingOnly(a:)" -new-name "betterName(b:)" >> %t.result/callsites_trailing_only.swift
|
||||
// RUN: diff -u %S/Outputs/callsites/trailing_only.swift.expected %t.result/callsites_trailing_only.swift
|
||||
// RUN: %refactor -syntactic-rename -source-filename %s -pos="varargs" -is-function-like -old-name "withVarargs(x:y:_:)" -new-name "betterName(a:b:c:)" >> %t.result/callsites_varargs.swift
|
||||
// RUN: diff -u %S/Outputs/callsites/varargs.swift.expected %t.result/callsites_varargs.swift
|
||||
// RUN: %refactor -syntactic-rename -source-filename %s -pos="varargs2" -is-function-like -old-name "withVarargs(x:y:_:)" -new-name "betterName(a:b:c:)" >> %t.result/callsites_varargs2.swift
|
||||
@@ -80,3 +86,5 @@ func /*mixed:def*/withAllOfTheAbove(x: Int = 2, _: Int..., z: Int = 2, c: () ->
|
||||
// RUN: diff -u %S/FindRangeOutputs/callsites/defaults.swift.expected %t.ranges/callsites_defaults.swift
|
||||
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="trailing" -is-function-like -old-name "withTrailingClosure(x:y:)" >> %t.ranges/callsites_trailing.swift
|
||||
// RUN: diff -u %S/FindRangeOutputs/callsites/trailing.swift.expected %t.ranges/callsites_trailing.swift
|
||||
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="trailing-only" -is-function-like -old-name "trailingOnly(a:)" >> %t.ranges/callsites_trailing_only.swift
|
||||
// RUN: diff -u %S/FindRangeOutputs/callsites/trailing_only.swift.expected %t.ranges/callsites_trailing_only.swift
|
||||
|
||||
Reference in New Issue
Block a user