Skip to content

Commit 00eaf74

Browse files
committed
[Refactoring] Move TrailingClosure to its own file
1 parent c7120f4 commit 00eaf74

File tree

3 files changed

+105
-89
lines changed

3 files changed

+105
-89
lines changed

lib/Refactoring/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_swift_host_library(swiftRefactoring STATIC
2222
Renamer.cpp
2323
ReplaceBodiesWithFatalError.cpp
2424
SimplifyNumberLiteral.cpp
25+
TrailingClosure.cpp
2526
Utils.cpp
2627
)
2728

lib/Refactoring/Refactoring.cpp

Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -566,95 +566,6 @@ collectRefactoringsAtCursor(SourceFile *SF, unsigned Line, unsigned Column,
566566
return collectRefactorings(Tok, /*ExcludeRename=*/false);
567567
}
568568

569-
static CallExpr *findTrailingClosureTarget(SourceManager &SM,
570-
ResolvedCursorInfoPtr CursorInfo) {
571-
if (CursorInfo->getKind() == CursorInfoKind::StmtStart)
572-
// StmtStart postion can't be a part of CallExpr.
573-
return nullptr;
574-
575-
// Find inner most CallExpr
576-
ContextFinder Finder(
577-
*CursorInfo->getSourceFile(), CursorInfo->getLoc(), [](ASTNode N) {
578-
return N.isStmt(StmtKind::Brace) || N.isExpr(ExprKind::Call);
579-
});
580-
Finder.resolve();
581-
auto contexts = Finder.getContexts();
582-
if (contexts.empty())
583-
return nullptr;
584-
585-
// If the innermost context is a statement (which will be a BraceStmt per
586-
// the filtering condition above), drop it.
587-
if (contexts.back().is<Stmt *>()) {
588-
contexts = contexts.drop_back();
589-
}
590-
591-
if (contexts.empty() || !contexts.back().is<Expr*>())
592-
return nullptr;
593-
CallExpr *CE = cast<CallExpr>(contexts.back().get<Expr*>());
594-
595-
// The last argument is a non-trailing closure?
596-
auto *Args = CE->getArgs();
597-
if (Args->empty() || Args->hasAnyTrailingClosures())
598-
return nullptr;
599-
600-
auto *LastArg = Args->back().getExpr();
601-
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(LastArg))
602-
LastArg = ICE->getSyntacticSubExpr();
603-
604-
if (isa<ClosureExpr>(LastArg) || isa<CaptureListExpr>(LastArg))
605-
return CE;
606-
return nullptr;
607-
}
608-
609-
bool RefactoringActionTrailingClosure::isApplicable(
610-
ResolvedCursorInfoPtr CursorInfo, DiagnosticEngine &Diag) {
611-
SourceManager &SM = CursorInfo->getSourceFile()->getASTContext().SourceMgr;
612-
return findTrailingClosureTarget(SM, CursorInfo);
613-
}
614-
615-
bool RefactoringActionTrailingClosure::performChange() {
616-
auto *CE = findTrailingClosureTarget(SM, CursorInfo);
617-
if (!CE)
618-
return true;
619-
620-
auto *ArgList = CE->getArgs()->getOriginalArgs();
621-
auto LParenLoc = ArgList->getLParenLoc();
622-
auto RParenLoc = ArgList->getRParenLoc();
623-
624-
if (LParenLoc.isInvalid() || RParenLoc.isInvalid())
625-
return true;
626-
627-
auto NumArgs = ArgList->size();
628-
if (NumArgs == 0)
629-
return true;
630-
631-
auto *ClosureArg = ArgList->getExpr(NumArgs - 1);
632-
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(ClosureArg))
633-
ClosureArg = ICE->getSyntacticSubExpr();
634-
635-
// Replace:
636-
// * Open paren with ' ' if the closure is sole argument.
637-
// * Comma with ') ' otherwise.
638-
if (NumArgs > 1) {
639-
auto *PrevArg = ArgList->getExpr(NumArgs - 2);
640-
CharSourceRange PreRange(
641-
SM,
642-
Lexer::getLocForEndOfToken(SM, PrevArg->getEndLoc()),
643-
ClosureArg->getStartLoc());
644-
EditConsumer.accept(SM, PreRange, ") ");
645-
} else {
646-
CharSourceRange PreRange(SM, LParenLoc, ClosureArg->getStartLoc());
647-
EditConsumer.accept(SM, PreRange, " ");
648-
}
649-
// Remove original closing paren.
650-
CharSourceRange PostRange(
651-
SM,
652-
Lexer::getLocForEndOfToken(SM, ClosureArg->getEndLoc()),
653-
Lexer::getLocForEndOfToken(SM, RParenLoc));
654-
EditConsumer.remove(SM, PostRange);
655-
return false;
656-
}
657-
658569
static bool collectRangeStartRefactorings(const ResolvedRangeInfo &Info) {
659570
switch (Info.Kind) {
660571
case RangeKind::SingleExpression:

lib/Refactoring/TrailingClosure.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "ContextFinder.h"
14+
#include "RefactoringActions.h"
15+
#include "swift/AST/Stmt.h"
16+
17+
using namespace swift::refactoring;
18+
19+
static CallExpr *findTrailingClosureTarget(SourceManager &SM,
20+
ResolvedCursorInfoPtr CursorInfo) {
21+
if (CursorInfo->getKind() == CursorInfoKind::StmtStart)
22+
// StmtStart postion can't be a part of CallExpr.
23+
return nullptr;
24+
25+
// Find inner most CallExpr
26+
ContextFinder Finder(
27+
*CursorInfo->getSourceFile(), CursorInfo->getLoc(), [](ASTNode N) {
28+
return N.isStmt(StmtKind::Brace) || N.isExpr(ExprKind::Call);
29+
});
30+
Finder.resolve();
31+
auto contexts = Finder.getContexts();
32+
if (contexts.empty())
33+
return nullptr;
34+
35+
// If the innermost context is a statement (which will be a BraceStmt per
36+
// the filtering condition above), drop it.
37+
if (contexts.back().is<Stmt *>()) {
38+
contexts = contexts.drop_back();
39+
}
40+
41+
if (contexts.empty() || !contexts.back().is<Expr *>())
42+
return nullptr;
43+
CallExpr *CE = cast<CallExpr>(contexts.back().get<Expr *>());
44+
45+
// The last argument is a non-trailing closure?
46+
auto *Args = CE->getArgs();
47+
if (Args->empty() || Args->hasAnyTrailingClosures())
48+
return nullptr;
49+
50+
auto *LastArg = Args->back().getExpr();
51+
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(LastArg))
52+
LastArg = ICE->getSyntacticSubExpr();
53+
54+
if (isa<ClosureExpr>(LastArg) || isa<CaptureListExpr>(LastArg))
55+
return CE;
56+
return nullptr;
57+
}
58+
59+
bool RefactoringActionTrailingClosure::isApplicable(
60+
ResolvedCursorInfoPtr CursorInfo, DiagnosticEngine &Diag) {
61+
SourceManager &SM = CursorInfo->getSourceFile()->getASTContext().SourceMgr;
62+
return findTrailingClosureTarget(SM, CursorInfo);
63+
}
64+
65+
bool RefactoringActionTrailingClosure::performChange() {
66+
auto *CE = findTrailingClosureTarget(SM, CursorInfo);
67+
if (!CE)
68+
return true;
69+
70+
auto *ArgList = CE->getArgs()->getOriginalArgs();
71+
auto LParenLoc = ArgList->getLParenLoc();
72+
auto RParenLoc = ArgList->getRParenLoc();
73+
74+
if (LParenLoc.isInvalid() || RParenLoc.isInvalid())
75+
return true;
76+
77+
auto NumArgs = ArgList->size();
78+
if (NumArgs == 0)
79+
return true;
80+
81+
auto *ClosureArg = ArgList->getExpr(NumArgs - 1);
82+
if (auto *ICE = dyn_cast<ImplicitConversionExpr>(ClosureArg))
83+
ClosureArg = ICE->getSyntacticSubExpr();
84+
85+
// Replace:
86+
// * Open paren with ' ' if the closure is sole argument.
87+
// * Comma with ') ' otherwise.
88+
if (NumArgs > 1) {
89+
auto *PrevArg = ArgList->getExpr(NumArgs - 2);
90+
CharSourceRange PreRange(
91+
SM, Lexer::getLocForEndOfToken(SM, PrevArg->getEndLoc()),
92+
ClosureArg->getStartLoc());
93+
EditConsumer.accept(SM, PreRange, ") ");
94+
} else {
95+
CharSourceRange PreRange(SM, LParenLoc, ClosureArg->getStartLoc());
96+
EditConsumer.accept(SM, PreRange, " ");
97+
}
98+
// Remove original closing paren.
99+
CharSourceRange PostRange(
100+
SM, Lexer::getLocForEndOfToken(SM, ClosureArg->getEndLoc()),
101+
Lexer::getLocForEndOfToken(SM, RParenLoc));
102+
EditConsumer.remove(SM, PostRange);
103+
return false;
104+
}

0 commit comments

Comments
 (0)