Skip to content

Commit fc3f7a0

Browse files
committed
[Refactoring] Move ConvertToTernaryExpr to its own file
1 parent a45cd03 commit fc3f7a0

File tree

3 files changed

+206
-189
lines changed

3 files changed

+206
-189
lines changed

lib/Refactoring/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_swift_host_library(swiftRefactoring STATIC
22
CollapseNestedIfStmt.cpp
33
ConvertStringConcatenationToInterpolation.cpp
44
ConvertToSwitchStmt.cpp
5+
ConvertToTernaryExpr.cpp
56
ExtractRepeatedExpr.cpp
67
MoveMembersToExtension.cpp
78
Refactoring.cpp
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
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 "RefactoringActions.h"
14+
#include "swift/AST/Stmt.h"
15+
16+
using namespace swift::refactoring;
17+
18+
/// Struct containing info about an IfStmt that can be converted into a
19+
/// TernaryExpr.
20+
struct ConvertToTernaryExprInfo {
21+
ConvertToTernaryExprInfo() {}
22+
23+
Expr *AssignDest() {
24+
25+
if (!Then || !Then->getDest() || !Else || !Else->getDest())
26+
return nullptr;
27+
28+
auto ThenDest = Then->getDest();
29+
auto ElseDest = Else->getDest();
30+
31+
if (ThenDest->getKind() != ElseDest->getKind())
32+
return nullptr;
33+
34+
switch (ThenDest->getKind()) {
35+
case ExprKind::DeclRef: {
36+
auto ThenRef = dyn_cast<DeclRefExpr>(Then->getDest());
37+
auto ElseRef = dyn_cast<DeclRefExpr>(Else->getDest());
38+
39+
if (!ThenRef || !ThenRef->getDecl() || !ElseRef || !ElseRef->getDecl())
40+
return nullptr;
41+
42+
const auto ThenName = ThenRef->getDecl()->getName();
43+
const auto ElseName = ElseRef->getDecl()->getName();
44+
45+
if (ThenName.compare(ElseName) != 0)
46+
return nullptr;
47+
48+
return Then->getDest();
49+
}
50+
case ExprKind::Tuple: {
51+
auto ThenTuple = dyn_cast<TupleExpr>(Then->getDest());
52+
auto ElseTuple = dyn_cast<TupleExpr>(Else->getDest());
53+
54+
if (!ThenTuple || !ElseTuple)
55+
return nullptr;
56+
57+
auto ThenNames = ThenTuple->getElementNames();
58+
auto ElseNames = ElseTuple->getElementNames();
59+
60+
if (!ThenNames.equals(ElseNames))
61+
return nullptr;
62+
63+
return ThenTuple;
64+
}
65+
default:
66+
return nullptr;
67+
}
68+
}
69+
70+
Expr *ThenSrc() {
71+
if (!Then)
72+
return nullptr;
73+
return Then->getSrc();
74+
}
75+
76+
Expr *ElseSrc() {
77+
if (!Else)
78+
return nullptr;
79+
return Else->getSrc();
80+
}
81+
82+
bool isValid() {
83+
if (!Cond || !AssignDest() || !ThenSrc() || !ElseSrc() ||
84+
!IfRange.isValid())
85+
return false;
86+
87+
return true;
88+
}
89+
90+
PatternBindingDecl *Binding = nullptr; // optional
91+
92+
Expr *Cond = nullptr; // required
93+
AssignExpr *Then = nullptr; // required
94+
AssignExpr *Else = nullptr; // required
95+
SourceRange IfRange;
96+
};
97+
98+
ConvertToTernaryExprInfo
99+
findConvertToTernaryExpression(const ResolvedRangeInfo &Info) {
100+
101+
auto notFound = ConvertToTernaryExprInfo();
102+
103+
if (Info.Kind != RangeKind::SingleStatement &&
104+
Info.Kind != RangeKind::MultiStatement)
105+
return notFound;
106+
107+
if (Info.ContainedNodes.empty())
108+
return notFound;
109+
110+
struct AssignExprFinder : public SourceEntityWalker {
111+
112+
AssignExpr *Assign = nullptr;
113+
114+
AssignExprFinder(Stmt *S) {
115+
if (S)
116+
walk(S);
117+
}
118+
119+
virtual bool walkToExprPre(Expr *E) override {
120+
Assign = dyn_cast<AssignExpr>(E);
121+
return false;
122+
}
123+
};
124+
125+
ConvertToTernaryExprInfo Target;
126+
127+
IfStmt *If = nullptr;
128+
129+
if (Info.ContainedNodes.size() == 1) {
130+
if (auto S = Info.ContainedNodes[0].dyn_cast<Stmt *>())
131+
If = dyn_cast<IfStmt>(S);
132+
}
133+
134+
if (Info.ContainedNodes.size() == 2) {
135+
if (auto D = Info.ContainedNodes[0].dyn_cast<Decl *>())
136+
Target.Binding = dyn_cast<PatternBindingDecl>(D);
137+
if (auto S = Info.ContainedNodes[1].dyn_cast<Stmt *>())
138+
If = dyn_cast<IfStmt>(S);
139+
}
140+
141+
if (!If)
142+
return notFound;
143+
144+
auto CondList = If->getCond();
145+
146+
if (CondList.size() != 1)
147+
return notFound;
148+
149+
Target.Cond = CondList[0].getBooleanOrNull();
150+
Target.IfRange = If->getSourceRange();
151+
152+
Target.Then = AssignExprFinder(If->getThenStmt()).Assign;
153+
Target.Else = AssignExprFinder(If->getElseStmt()).Assign;
154+
155+
return Target;
156+
}
157+
158+
bool RefactoringActionConvertToTernaryExpr::isApplicable(
159+
const ResolvedRangeInfo &Info, DiagnosticEngine &Diag) {
160+
return findConvertToTernaryExpression(Info).isValid();
161+
}
162+
163+
bool RefactoringActionConvertToTernaryExpr::performChange() {
164+
auto Target = findConvertToTernaryExpression(RangeInfo);
165+
166+
if (!Target.isValid())
167+
return true; // abort
168+
169+
SmallString<64> DeclBuffer;
170+
llvm::raw_svector_ostream OS(DeclBuffer);
171+
172+
StringRef Space = " ";
173+
174+
auto IfRange = Target.IfRange;
175+
auto ReplaceRange = Lexer::getCharSourceRangeFromSourceRange(SM, IfRange);
176+
177+
auto CondRange = Target.Cond->getSourceRange();
178+
auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, CondRange);
179+
180+
auto ThenRange = Target.ThenSrc()->getSourceRange();
181+
auto ThenCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ThenRange);
182+
183+
auto ElseRange = Target.ElseSrc()->getSourceRange();
184+
auto ElseCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ElseRange);
185+
186+
CharSourceRange DestCharRange;
187+
188+
if (Target.Binding) {
189+
auto DestRange = Target.Binding->getSourceRange();
190+
DestCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, DestRange);
191+
ReplaceRange.widen(DestCharRange);
192+
} else {
193+
auto DestRange = Target.AssignDest()->getSourceRange();
194+
DestCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, DestRange);
195+
}
196+
197+
OS << DestCharRange.str() << Space << tok::equal << Space;
198+
OS << CondCharRange.str() << Space << tok::question_postfix << Space;
199+
OS << ThenCharRange.str() << Space << tok::colon << Space;
200+
OS << ElseCharRange.str();
201+
202+
EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());
203+
204+
return false; // don't abort
205+
}

0 commit comments

Comments
 (0)