[IDE][Refactoring] Update syntactic rename to support braceless multiple trailing closures.

This commit is contained in:
Nathan Hawes
2020-04-20 19:18:25 -07:00
committed by John McCall
parent 58859f5699
commit 78b7bce3a0
18 changed files with 178 additions and 83 deletions

View File

@@ -222,6 +222,7 @@ struct ResolvedLoc {
ASTWalker::ParentTy Node;
CharSourceRange Range;
std::vector<CharSourceRange> LabelRanges;
Optional<unsigned> FirstTrailingLabel;
LabelRangeType LabelType;
bool IsActive;
bool IsInSelector;
@@ -268,7 +269,8 @@ class NameMatcher: public ASTWalker {
bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc);
bool tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc, Expr *Arg);
bool tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc, LabelRangeType RangeType,
ArrayRef<CharSourceRange> LabelLocs);
ArrayRef<CharSourceRange> LabelLocs,
Optional<unsigned> FirstTrailingLabel);
bool handleCustomAttrs(Decl *D);
Expr *getApplicableArgFor(Expr* E);
@@ -579,10 +581,10 @@ struct CallArgInfo {
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>
// Get the ranges of argument labels from an Arg, either tuple or paren, and
// the index of the first trailing closure argument, if any. This includes empty
// ranges for any unlabelled arguments, including the first trailing closure.
std::pair<std::vector<CharSourceRange>, Optional<unsigned>>
getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind);
/// Whether a decl is defined from clang source.

View File

@@ -108,10 +108,12 @@ public:
/// Adds replacements to rename the given label ranges
/// \return true if the label ranges do not match the old name
bool renameLabels(ArrayRef<CharSourceRange> LabelRanges,
Optional<unsigned> FirstTrailingLabel,
LabelRangeType RangeType, bool isCallSite) {
if (isCallSite)
return renameLabelsLenient(LabelRanges, RangeType);
return renameLabelsLenient(LabelRanges, FirstTrailingLabel, RangeType);
assert(!FirstTrailingLabel);
ArrayRef<StringRef> OldLabels = Old.args();
if (OldLabels.size() != LabelRanges.size())
@@ -261,10 +263,56 @@ private:
}
bool renameLabelsLenient(ArrayRef<CharSourceRange> LabelRanges,
Optional<unsigned> FirstTrailingLabel,
LabelRangeType RangeType) {
ArrayRef<StringRef> OldNames = Old.args();
// First, match trailing closure arguments in reverse
if (FirstTrailingLabel) {
auto TrailingLabels = LabelRanges.drop_front(*FirstTrailingLabel);
LabelRanges = LabelRanges.take_front(*FirstTrailingLabel);
for (auto LabelIndex: llvm::reverse(indices(TrailingLabels))) {
CharSourceRange Label = TrailingLabels[LabelIndex];
if (Label.getByteLength()) {
if (OldNames.empty())
return true;
while (!labelRangeMatches(Label, LabelRangeType::Selector,
OldNames.back())) {
if ((OldNames = OldNames.drop_back()).empty())
return true;
}
splitAndRenameLabel(Label, LabelRangeType::Selector,
OldNames.size() - 1);
OldNames = OldNames.drop_back();
continue;
}
// empty labelled trailing closure label
if (LabelIndex) {
if (OldNames.empty())
return true;
while (!OldNames.back().empty()) {
if ((OldNames = OldNames.drop_back()).empty())
return true;
}
splitAndRenameLabel(Label, LabelRangeType::Selector,
OldNames.size() - 1);
OldNames = OldNames.drop_back();
continue;
}
// unlabelled trailing closure label
OldNames = OldNames.drop_back();
continue;
}
}
// Next, match the non-trailing arguments.
size_t NameIndex = 0;
for (CharSourceRange Label : LabelRanges) {
@@ -399,7 +447,8 @@ public:
(Config.Usage != NameUsage::Reference || IsSubscript) &&
Resolved.LabelType == LabelRangeType::CallArg;
if (renameLabels(Resolved.LabelRanges, Resolved.LabelType, isCallSite))
if (renameLabels(Resolved.LabelRanges, Resolved.FirstTrailingLabel,
Resolved.LabelType, isCallSite))
return Config.Usage == NameUsage::Unknown ?
RegionType::Unmatched : RegionType::Mismatch;
}

View File

@@ -102,7 +102,7 @@ std::vector<ResolvedLoc> NameMatcher::resolve(ArrayRef<UnresolvedLoc> Locs, Arra
// handle any unresolved locs past the end of the last AST node or comment
std::vector<ResolvedLoc> Remaining(Locs.size() - ResolvedLocs.size(), {
ASTWalker::ParentTy(), CharSourceRange(), {}, LabelRangeType::None,
ASTWalker::ParentTy(), CharSourceRange(), {}, None, LabelRangeType::None,
/*isActice*/true, /*isInSelector*/false});
ResolvedLocs.insert(ResolvedLocs.end(), Remaining.begin(), Remaining.end());
@@ -238,15 +238,15 @@ bool NameMatcher::walkToDeclPre(Decl *D) {
LabelRanges = getLabelRanges(ParamList, getSourceMgr());
}
tryResolve(ASTWalker::ParentTy(D), D->getLoc(), LabelRangeType::Param,
LabelRanges);
LabelRanges, None);
} else if (SubscriptDecl *SD = dyn_cast<SubscriptDecl>(D)) {
tryResolve(ASTWalker::ParentTy(D), D->getLoc(), LabelRangeType::NoncollapsibleParam,
getLabelRanges(SD->getIndices(), getSourceMgr()));
getLabelRanges(SD->getIndices(), getSourceMgr()), None);
} else if (EnumElementDecl *EED = dyn_cast<EnumElementDecl>(D)) {
if (auto *ParamList = EED->getParameterList()) {
auto LabelRanges = getEnumParamListInfo(getSourceMgr(), ParamList);
tryResolve(ASTWalker::ParentTy(D), D->getLoc(), LabelRangeType::CallArg,
LabelRanges);
LabelRanges, None);
} else {
tryResolve(ASTWalker::ParentTy(D), D->getLoc());
}
@@ -362,7 +362,8 @@ std::pair<bool, Expr*> NameMatcher::walkToExprPre(Expr *E) {
auto Labels = getCallArgLabelRanges(getSourceMgr(), SubExpr->getIndex(),
LabelRangeEndAt::BeforeElemStart);
tryResolve(ASTWalker::ParentTy(E), E->getLoc(), LabelRangeType::CallArg, Labels);
tryResolve(ASTWalker::ParentTy(E), E->getLoc(), LabelRangeType::CallArg,
Labels.first, Labels.second);
if (isDone())
break;
if (!SubExpr->getIndex()->walk(*this))
@@ -379,7 +380,7 @@ std::pair<bool, Expr*> NameMatcher::walkToExprPre(Expr *E) {
auto Labels = getCallArgLabelRanges(getSourceMgr(), P,
LabelRangeEndAt::BeforeElemStart);
tryResolve(ASTWalker::ParentTy(E), P->getLParenLoc(),
LabelRangeType::CallArg, Labels);
LabelRangeType::CallArg, Labels.first, Labels.second);
break;
}
case ExprKind::Tuple: {
@@ -388,7 +389,7 @@ std::pair<bool, Expr*> NameMatcher::walkToExprPre(Expr *E) {
auto Labels = getCallArgLabelRanges(getSourceMgr(), T,
LabelRangeEndAt::BeforeElemStart);
tryResolve(ASTWalker::ParentTy(E), T->getLParenLoc(),
LabelRangeType::CallArg, Labels);
LabelRangeType::CallArg, Labels.first, Labels.second);
if (isDone())
break;
@@ -485,8 +486,10 @@ bool NameMatcher::walkToTypeReprPre(TypeRepr *T) {
// If we're walking a CustomAttr's type we may have an associated call
// argument to resolve with from its semantic initializer.
if (CustomAttrArg.hasValue() && CustomAttrArg->Loc == T->getLoc()) {
auto Labels = getCallArgLabelRanges(getSourceMgr(), CustomAttrArg->Item,
LabelRangeEndAt::BeforeElemStart);
tryResolve(ASTWalker::ParentTy(T), T->getLoc(), LabelRangeType::CallArg,
getCallArgLabelRanges(getSourceMgr(), CustomAttrArg->Item, LabelRangeEndAt::BeforeElemStart));
Labels.first, Labels.second);
} else {
tryResolve(ASTWalker::ParentTy(T), T->getLoc());
}
@@ -527,7 +530,7 @@ void NameMatcher::skipLocsBefore(SourceLoc Start) {
if (!checkComments()) {
LocsToResolve.pop_back();
ResolvedLocs.push_back({ASTWalker::ParentTy(), CharSourceRange(), {},
LabelRangeType::None, isActive(), isInSelector()});
None, LabelRangeType::None, isActive(), isInSelector()});
}
}
}
@@ -592,7 +595,7 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc,
if (NameLoc.isCompound()) {
auto Labels = getSelectorLabelRanges(getSourceMgr(), NameLoc);
bool Resolved = tryResolve(Node, NameLoc.getBaseNameLoc(),
LabelRangeType::Selector, Labels);
LabelRangeType::Selector, Labels, None);
if (!isDone()) {
for (auto Label: Labels) {
if (tryResolve(Node, Label.getStart())) {
@@ -606,10 +609,12 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc,
}
if (LocsToResolve.back().ResolveArgLocs) {
if (Arg)
if (Arg) {
auto Labels = getCallArgLabelRanges(getSourceMgr(), Arg,
LabelRangeEndAt::BeforeElemStart);
return tryResolve(Node, NameLoc.getBaseNameLoc(), LabelRangeType::CallArg,
getCallArgLabelRanges(getSourceMgr(), Arg,
LabelRangeEndAt::BeforeElemStart));
Labels.first, Labels.second);
}
}
return tryResolve(Node, NameLoc.getBaseNameLoc());
@@ -617,12 +622,13 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, DeclNameLoc NameLoc,
bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc) {
assert(!isDone());
return tryResolve(Node, NameLoc, LabelRangeType::None, None);
return tryResolve(Node, NameLoc, LabelRangeType::None, None, None);
}
bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc,
LabelRangeType RangeType,
ArrayRef<CharSourceRange> LabelRanges) {
ArrayRef<CharSourceRange> LabelRanges,
Optional<unsigned> FirstTrailingLabel) {
skipLocsBefore(NameLoc);
if (isDone())
return false;
@@ -634,8 +640,8 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc,
if (Range.isValid()) {
if (NameLoc == Next.Loc) {
LocsToResolve.pop_back();
ResolvedLocs.push_back({Node, Range, LabelRanges, RangeType,
isActive(), isInSelector()});
ResolvedLocs.push_back({Node, Range, LabelRanges, FirstTrailingLabel,
RangeType, isActive(), isInSelector()});
if (isDone())
return true;
WasResolved = true;
@@ -649,7 +655,7 @@ bool NameMatcher::tryResolve(ASTWalker::ParentTy Node, SourceLoc NameLoc,
Range.getByteLength() - 1);
if (NewRange.getStart() == Next.Loc) {
LocsToResolve.pop_back();
ResolvedLocs.push_back({Node, NewRange, {}, LabelRangeType::None,
ResolvedLocs.push_back({Node, NewRange, {}, None, LabelRangeType::None,
isActive(), isInSelector()});
WasResolved = true;
}
@@ -881,6 +887,7 @@ std::vector<CallArgInfo> swift::ide::
getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) {
std::vector<CallArgInfo> InfoVec;
if (auto *TE = dyn_cast<TupleExpr>(Arg)) {
auto FirstTrailing = TE->getUnlabeledTrailingClosureIndexOfPackedArgument();
for (size_t ElemIndex: range(TE->getNumElements())) {
Expr *Elem = TE->getElement(ElemIndex);
if (isa<DefaultArgumentExpr>(Elem))
@@ -889,14 +896,14 @@ getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) {
SourceLoc LabelStart(Elem->getStartLoc());
SourceLoc LabelEnd(LabelStart);
auto NameIdentifier = TE->getElementName(ElemIndex);
if (!NameIdentifier.empty()) {
LabelStart = TE->getElementNameLoc(ElemIndex);
if (EndKind == LabelRangeEndAt::LabelNameOnly)
LabelEnd = LabelStart.getAdvancedLoc(NameIdentifier.getLength());
bool IsTrailingClosure = FirstTrailing && ElemIndex >= *FirstTrailing;
SourceLoc NameLoc = TE->getElementNameLoc(ElemIndex);
if (NameLoc.isValid()) {
LabelStart = NameLoc;
if (EndKind == LabelRangeEndAt::LabelNameOnly || IsTrailingClosure) {
LabelEnd = Lexer::getLocForEndOfToken(SM, NameLoc);
}
}
bool IsTrailingClosure = TE->hasTrailingClosure() &&
ElemIndex == TE->getNumElements() - 1;
InfoVec.push_back({getSingleNonImplicitChild(Elem),
CharSourceRange(SM, LabelStart, LabelEnd), IsTrailingClosure});
}
@@ -911,17 +918,19 @@ getCallArgInfo(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) {
return InfoVec;
}
std::vector<CharSourceRange> swift::ide::
std::pair<std::vector<CharSourceRange>, Optional<unsigned>> swift::ide::
getCallArgLabelRanges(SourceManager &SM, Expr *Arg, LabelRangeEndAt EndKind) {
std::vector<CharSourceRange> Ranges;
auto InfoVec = getCallArgInfo(SM, Arg, EndKind);
auto EndWithoutTrailing = std::remove_if(InfoVec.begin(), InfoVec.end(),
[](CallArgInfo &Info) {
Optional<unsigned> FirstTrailing;
auto I = std::find_if(InfoVec.begin(), InfoVec.end(), [](CallArgInfo &Info) {
return Info.IsTrailingClosure;
});
std::transform(InfoVec.begin(), EndWithoutTrailing,
std::back_inserter(Ranges),
if (I != InfoVec.end())
FirstTrailing = std::distance(InfoVec.begin(), I);
std::transform(InfoVec.begin(), InfoVec.end(), std::back_inserter(Ranges),
[](CallArgInfo &Info) { return Info.LabelRange; });
return Ranges;
return {Ranges, FirstTrailing};
}

View File

@@ -505,11 +505,16 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
auto Ranges = getCallArgLabelRanges(SM, Arg,
LabelRangeEndAt::LabelNameOnly);
llvm::SmallVector<uint8_t, 2> ToRemoveIndices;
for (unsigned I = 0; I < Ranges.size(); I ++) {
for (unsigned I = 0; I < Ranges.first.size(); I ++) {
if (std::any_of(IgnoreArgIndex.begin(), IgnoreArgIndex.end(),
[I](unsigned Ig) { return Ig == I; }))
continue;
auto LR = Ranges[I];
// Ignore the first trailing closure label
if (Ranges.second && I == Ranges.second)
continue;
auto LR = Ranges.first[I];
if (Idx < NewName.argSize()) {
auto Label = NewName.args()[Idx++];
@@ -528,7 +533,7 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker {
auto Ranges = getCallArgLabelRanges(SM, Arg,
LabelRangeEndAt::BeforeElemStart);
for (auto I : ToRemoveIndices) {
Editor.remove(Ranges[I]);
Editor.remove(Ranges.first[I]);
}
}
}

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ func /*trailing:def*/<base>withTrailingClosure</base>(<arglabel index=0>x</argla
// valid
/*trailing:call*/<base>withTrailingClosure</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>2, <callarg index=1>y</callarg><callcolon index=1>: </callcolon>{ return 1})
/*trailing:call*/<base>withTrailingClosure</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>2) { return 1}
// false positives
/*trailing:call*/<base>withTrailingClosure</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>1, <callarg index=1>y</callarg><callcolon index=1>: </callcolon>2) { return 1}
/*trailing:call*/<base>withTrailingClosure</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>1, <callarg index=1>y</callarg><callcolon index=1>: </callcolon>2) { return 1}
/*trailing:call*/<base>withTrailingClosure</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>2)
{ return 1}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 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>{})

View File

@@ -0,0 +1,9 @@
func /*test:def*/<base>test</base>(<arglabel index=0>x</arglabel><param index=0></param>: () -> () = {}, <arglabel index=1>_</arglabel><param index=1> xx</param>: () -> () = {}, <arglabel index=2>y</arglabel><param index=2></param>: () -> () = {}, <arglabel index=3>z</arglabel><param index=3></param>: ()->() = {}) {}
/*test:call*/<base>test</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>{}, <callcombo index=1></callcombo>{}) {}
/*test:call*/<base>test</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>{}) {} <sel index=3>z</sel>: {}
/*test:call*/<base>test</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>{}, <callcombo index=1></callcombo>{}) {}
/*test:call*/<base>test</base> {} <sel index=2>y</sel>: {}
/*test:call*/<base>test</base>(<callarg index=2>y</callarg><callcolon index=2>: </callcolon>{}) {}

View File

@@ -0,0 +1,8 @@
func /*test:def*/<base>test</base>(<arglabel index=0>x</arglabel><param index=0></param>: () -> (), <arglabel index=1>_</arglabel><param index=1> xx</param>: () -> (), <arglabel index=2>y</arglabel><param index=2></param>: () -> (), <arglabel index=3>z</arglabel><param index=3></param>: ()->()) {}
/*test:call*/<base>test</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>{}, <callcombo index=1></callcombo>{}, <callarg index=2>y</callarg><callcolon index=2>: </callcolon>{}) {}
/*test:call*/<base>test</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>{}, <callcombo index=1></callcombo>{}) {} <sel index=3>z</sel>: {}
/*test:call*/<base>test</base>(<callarg index=0>x</callarg><callcolon index=0>: </callcolon>{}) {} <sel index=2>y</sel>: {} <sel index=3>z</sel>: {}
/*test:call*/<base>test</base> {} <sel index=1>_</sel>: {} <sel index=2>y</sel>: {} <sel index=3>z</sel>: {}

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ func /*trailing:def*/betterName(a: Int, b: () -> Int) {}
// valid
/*trailing:call*/betterName(a: 2, b: { return 1})
/*trailing:call*/betterName(a: 2) { return 1}
// false positives
/*trailing:call*/betterName(a: 1, b: 2) { return 1}
/*trailing:call*/betterName(a: 1, b: 2) { return 1}
/*trailing:call*/betterName(a: 2)
{ return 1}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/betterName(b: () -> ()) {}
/*trailing-only:call*/betterName(b: {})

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -21,12 +21,11 @@ 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}
// invalid
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
/*trailing:call*/withTrailingClosure(x: 1, y: 2) { return 1}
func /*trailing-only:def*/trailingOnly(a: () -> ()) {}
/*trailing-only:call*/trailingOnly(a: {})

View File

@@ -0,0 +1,12 @@
func /*test:def*/test(x: () -> () = {}, _ xx: () -> () = {}, y: () -> () = {}, z: ()->() = {}) {}
/*test:call*/test(x: {}, {}) {}
/*test:call*/test(x: {}) {} z: {}
/*test:call*/test(x: {}, {}) {}
/*test:call*/test {} y: {}
/*test:call*/test(y: {}) {}
// RUN: %empty-directory(%t.ranges)
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="test" -is-function-like -old-name "test(x:_:y:z:)" >> %t.ranges/multiple-trailing-closures-defaulted.swift.expected
// RUN: diff -u %S/FindRangeOutputs/multiple-trailing-closures-defaulted.swift.expected %t.ranges/multiple-trailing-closures-defaulted.swift.expected

View File

@@ -0,0 +1,11 @@
func /*test:def*/test(x: () -> (), _ xx: () -> (), y: () -> (), z: ()->()) {}
/*test:call*/test(x: {}, {}, y: {}) {}
/*test:call*/test(x: {}, {}) {} z: {}
/*test:call*/test(x: {}) {} y: {} z: {}
/*test:call*/test {} _: {} y: {} z: {}
// RUN: %empty-directory(%t.ranges)
// RUN: %refactor -find-rename-ranges -source-filename %s -pos="test" -is-function-like -old-name "test(x:_:y:z:)" >> %t.ranges/multiple-trailing-closures.swift.expected
// RUN: diff -u %S/FindRangeOutputs/multiple-trailing-closures.swift.expected %t.ranges/multiple-trailing-closures.swift.expected