-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Refactoring] SR-5743 Try To Force Try Refactor implementation #12128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1973,6 +1973,89 @@ bool RefactoringActionConvertToDoCatch::performChange() { | |
return false; | ||
} | ||
|
||
struct TryExpressionConversionInfo { | ||
TryExpr &TE; | ||
DoCatchStmt *Stmt; | ||
unsigned int NumberOfTriesInDoCatch; | ||
TryExpressionConversionInfo(TryExpr &TE, DoCatchStmt *Stmt, | ||
unsigned int NumberOfTriesInDoCatch): | ||
TE(TE), | ||
Stmt(Stmt), | ||
NumberOfTriesInDoCatch(NumberOfTriesInDoCatch) {} | ||
TryExpressionConversionInfo(TryExpr &TE): TE(TE), Stmt(nullptr), | ||
NumberOfTriesInDoCatch(0) {} | ||
}; | ||
|
||
static TryExpressionConversionInfo findTryConversion(ResolvedCursorInfo Info, | ||
SourceFile *TheFile, | ||
SourceManager &SM) { | ||
auto *TE = dyn_cast<TryExpr>(Info.TrailingExpr); | ||
assert(TE); | ||
auto Node = ASTNode(TE); | ||
auto NodeChecker = [](ASTNode N) { | ||
return N.isStmt(StmtKind::DoCatch); | ||
}; | ||
ContextFinder Finder(*TheFile, Node, NodeChecker); | ||
Finder.resolve(); | ||
auto Contexts = Finder.getContexts(); | ||
if (Contexts.size() == 0) { | ||
return TryExpressionConversionInfo(*TE); | ||
} | ||
auto StmtNode = Contexts.back(); | ||
DoCatchStmt *DCStmt = dyn_cast<DoCatchStmt>(StmtNode.dyn_cast<Stmt*>()); | ||
|
||
struct TryExprCounter: public SourceEntityWalker { | ||
unsigned int Count = 0; | ||
bool walkToExprPre(Expr *E) { | ||
if (auto *FE = dyn_cast<TryExpr>(E)) { | ||
Count += 1; | ||
} | ||
return true; | ||
} | ||
} Counter; | ||
Counter.walk(DCStmt); | ||
|
||
return TryExpressionConversionInfo(*TE, DCStmt, Counter.Count); | ||
} | ||
|
||
bool RefactoringActionConvertToForceTry:: | ||
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) { | ||
if (!Tok.TrailingExpr) | ||
return false; | ||
return isa<TryExpr>(Tok.TrailingExpr); | ||
} | ||
|
||
bool RefactoringActionConvertToForceTry::performChange() { | ||
auto ConversionInfo = findTryConversion(CursorInfo, TheFile, SM); | ||
auto *DCStmt = ConversionInfo.Stmt; | ||
// Add exclamation to the call. | ||
auto TryLoc = ConversionInfo.TE.getTryLoc(); | ||
auto TryEndLoc = TryLoc.getAdvancedLocOrInvalid(getKeywordLen(tok::kw_try)); | ||
EditConsumer.accept(SM, TryEndLoc, "!"); | ||
|
||
if (DCStmt && ConversionInfo.NumberOfTriesInDoCatch == 1) { | ||
//It's the only try in do catch block, remove the block. | ||
auto *BodyStmt = DCStmt->getBody(); | ||
auto *BCStmt = dyn_cast<BraceStmt>(BodyStmt); | ||
auto FirstNodeStartLoc = BCStmt->getElements().front().getStartLoc(); | ||
auto BeforeBodyRange = CharSourceRange( | ||
SM, | ||
DCStmt->getStartLoc(), | ||
FirstNodeStartLoc); | ||
EditConsumer.accept(SM, BeforeBodyRange, ""); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a method in |
||
auto LastNodePastEndLoc = BCStmt->getElements() | ||
.back().getEndLoc().getAdvancedLocOrInvalid(1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are not sure the last token is of length |
||
auto CatchRBraceLoc = DCStmt->getEndLoc() | ||
.getAdvancedLocOrInvalid(getKeywordLen(tok::r_paren)); | ||
auto AfterBodyRange = CharSourceRange( | ||
SM, | ||
LastNodePastEndLoc, | ||
CatchRBraceLoc); | ||
EditConsumer.accept(SM, AfterBodyRange, ""); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the newly added |
||
} | ||
return false; | ||
} | ||
|
||
/// Given a cursor position, this function tries to collect a number literal | ||
/// expression immediately following the cursor. | ||
static NumberLiteralExpr *getTrailingNumberLiteral(ResolvedCursorInfo Tok) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
func testTryToForceTry() { | ||
func throwingFunc() throws -> Int { return 3 } | ||
do { | ||
let _ = try! throwingFunc() | ||
let _ = try throwingFunc() | ||
} catch { | ||
let _ = error | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
func testTryToForceTry() { | ||
func throwingFunc() throws -> Int { return 3 } | ||
let _ = try! throwingFunc() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
func testTryToForceTry() { | ||
func throwingFunc() throws -> Int { return 3 } | ||
let _ = try! throwingFunc() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
func testTryToForceTry() { | ||
func throwingFunc() throws -> Int { return 3 } | ||
do { | ||
let _ = try throwingFunc() | ||
let _ = try throwingFunc() | ||
} catch { | ||
let _ = error | ||
} | ||
} | ||
// RUN: rm -rf %t.result && mkdir -p %t.result | ||
// RUN: %refactor -convert-to-force-try -source-filename %s -pos=4:14 > %t.result/L4.swift | ||
// RUN: diff -u %S/Outputs/multiple_tries/L4.swift.expected %t.result/L4.swift |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
func testTryToForceTry() { | ||
func throwingFunc() throws -> Int { return 3 } | ||
do { | ||
let _ = try throwingFunc() | ||
} catch { | ||
let _ = error | ||
} | ||
} | ||
// RUN: rm -rf %t.result && mkdir -p %t.result | ||
// RUN: %refactor -convert-to-force-try -source-filename %s -pos=4:14 > %t.result/L3.swift | ||
// RUN: diff -u %S/Outputs/only_try/L3.swift.expected %t.result/L3.swift |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
func testTryToForceTry() { | ||
func throwingFunc() throws -> Int { return 3 } | ||
let _ = try throwingFunc() | ||
} | ||
// RUN: rm -rf %t.result && mkdir -p %t.result | ||
// RUN: %refactor -convert-to-force-try -source-filename %s -pos=3:12 > %t.result/L3.swift | ||
// RUN: diff -u %S/Outputs/try_without_do/L3.swift.expected %t.result/L3.swift |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we don't need
FE
; soisa<TryExpr>(E)
is sufficient.