Skip to content

Commit d09be61

Browse files
committed
[Refactoring] Move ExpandTernaryExpr to its own file
1 parent 563674f commit d09be61

File tree

3 files changed

+218
-203
lines changed

3 files changed

+218
-203
lines changed

lib/Refactoring/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_swift_host_library(swiftRefactoring STATIC
55
ConvertIfLetExprToGuardExpr.cpp
66
ConvertToSwitchStmt.cpp
77
ConvertToTernaryExpr.cpp
8+
ExpandTernaryExpr.cpp
89
ExtractExpr.cpp
910
ExtractExprBase.cpp
1011
ExtractRepeatedExpr.cpp

lib/Refactoring/ExpandTernaryExpr.cpp

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
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/Pattern.h"
15+
16+
using namespace swift::refactoring;
17+
18+
namespace {
19+
/// Abstract helper class containing info about a TernaryExpr
20+
/// that can be expanded into an IfStmt.
21+
class ExpandableTernaryExprInfo {
22+
23+
public:
24+
virtual ~ExpandableTernaryExprInfo() {}
25+
26+
virtual TernaryExpr *getTernary() = 0;
27+
28+
virtual SourceRange getNameRange() = 0;
29+
30+
virtual Type getType() = 0;
31+
32+
virtual bool shouldDeclareNameAndType() { return !getType().isNull(); }
33+
34+
virtual bool isValid() {
35+
36+
// Ensure all public properties are non-nil and valid
37+
if (!getTernary() || !getNameRange().isValid())
38+
return false;
39+
if (shouldDeclareNameAndType() && getType().isNull())
40+
return false;
41+
42+
return true; // valid
43+
}
44+
45+
CharSourceRange getNameCharRange(const SourceManager &SM) {
46+
return Lexer::getCharSourceRangeFromSourceRange(SM, getNameRange());
47+
}
48+
};
49+
50+
/// Concrete subclass containing info about an AssignExpr
51+
/// where the source is the expandable TernaryExpr.
52+
class ExpandableAssignTernaryExprInfo : public ExpandableTernaryExprInfo {
53+
54+
public:
55+
ExpandableAssignTernaryExprInfo(AssignExpr *Assign) : Assign(Assign) {}
56+
57+
TernaryExpr *getTernary() override {
58+
if (!Assign)
59+
return nullptr;
60+
return dyn_cast_or_null<TernaryExpr>(Assign->getSrc());
61+
}
62+
63+
SourceRange getNameRange() override {
64+
auto Invalid = SourceRange();
65+
66+
if (!Assign)
67+
return Invalid;
68+
69+
if (auto dest = Assign->getDest())
70+
return dest->getSourceRange();
71+
72+
return Invalid;
73+
}
74+
75+
Type getType() override { return nullptr; }
76+
77+
private:
78+
AssignExpr *Assign = nullptr;
79+
};
80+
81+
/// Concrete subclass containing info about a PatternBindingDecl
82+
/// where the pattern initializer is the expandable TernaryExpr.
83+
class ExpandableBindingTernaryExprInfo : public ExpandableTernaryExprInfo {
84+
85+
public:
86+
ExpandableBindingTernaryExprInfo(PatternBindingDecl *Binding)
87+
: Binding(Binding) {}
88+
89+
TernaryExpr *getTernary() override {
90+
if (Binding && Binding->getNumPatternEntries() == 1) {
91+
if (auto *Init = Binding->getInit(0)) {
92+
return dyn_cast<TernaryExpr>(Init);
93+
}
94+
}
95+
96+
return nullptr;
97+
}
98+
99+
SourceRange getNameRange() override {
100+
if (auto Pattern = getNamePattern())
101+
return Pattern->getSourceRange();
102+
103+
return SourceRange();
104+
}
105+
106+
Type getType() override {
107+
if (auto Pattern = getNamePattern())
108+
return Pattern->getType();
109+
110+
return nullptr;
111+
}
112+
113+
private:
114+
Pattern *getNamePattern() {
115+
if (!Binding || Binding->getNumPatternEntries() != 1)
116+
return nullptr;
117+
118+
auto Pattern = Binding->getPattern(0);
119+
120+
if (!Pattern)
121+
return nullptr;
122+
123+
if (auto TyPattern = dyn_cast<TypedPattern>(Pattern))
124+
Pattern = TyPattern->getSubPattern();
125+
126+
return Pattern;
127+
}
128+
129+
PatternBindingDecl *Binding = nullptr;
130+
};
131+
132+
std::unique_ptr<ExpandableTernaryExprInfo>
133+
findExpandableTernaryExpression(const ResolvedRangeInfo &Info) {
134+
135+
if (Info.Kind != RangeKind::SingleDecl &&
136+
Info.Kind != RangeKind::SingleExpression)
137+
return nullptr;
138+
139+
if (Info.ContainedNodes.size() != 1)
140+
return nullptr;
141+
142+
if (auto D = Info.ContainedNodes[0].dyn_cast<Decl *>())
143+
if (auto Binding = dyn_cast<PatternBindingDecl>(D))
144+
return std::make_unique<ExpandableBindingTernaryExprInfo>(Binding);
145+
146+
if (auto E = Info.ContainedNodes[0].dyn_cast<Expr *>())
147+
if (auto Assign = dyn_cast<AssignExpr>(E))
148+
return std::make_unique<ExpandableAssignTernaryExprInfo>(Assign);
149+
150+
return nullptr;
151+
}
152+
} // namespace
153+
154+
bool RefactoringActionExpandTernaryExpr::isApplicable(
155+
const ResolvedRangeInfo &Info, DiagnosticEngine &Diag) {
156+
auto Target = findExpandableTernaryExpression(Info);
157+
return Target && Target->isValid();
158+
}
159+
160+
bool RefactoringActionExpandTernaryExpr::performChange() {
161+
auto Target = findExpandableTernaryExpression(RangeInfo);
162+
163+
if (!Target || !Target->isValid())
164+
return true; // abort
165+
166+
auto NameCharRange = Target->getNameCharRange(SM);
167+
168+
auto IfRange = Target->getTernary()->getSourceRange();
169+
auto IfCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, IfRange);
170+
171+
auto CondRange = Target->getTernary()->getCondExpr()->getSourceRange();
172+
auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, CondRange);
173+
174+
auto ThenRange = Target->getTernary()->getThenExpr()->getSourceRange();
175+
auto ThenCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ThenRange);
176+
177+
auto ElseRange = Target->getTernary()->getElseExpr()->getSourceRange();
178+
auto ElseCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ElseRange);
179+
180+
SmallString<64> DeclBuffer;
181+
llvm::raw_svector_ostream OS(DeclBuffer);
182+
183+
StringRef Space = " ";
184+
StringRef NewLine = "\n";
185+
186+
if (Target->shouldDeclareNameAndType()) {
187+
// Specifier will not be replaced; append after specifier
188+
OS << NameCharRange.str() << tok::colon << Space;
189+
OS << Target->getType() << NewLine;
190+
}
191+
192+
OS << tok::kw_if << Space;
193+
OS << CondCharRange.str() << Space;
194+
OS << tok::l_brace << NewLine;
195+
196+
OS << NameCharRange.str() << Space;
197+
OS << tok::equal << Space;
198+
OS << ThenCharRange.str() << NewLine;
199+
200+
OS << tok::r_brace << Space;
201+
OS << tok::kw_else << Space;
202+
OS << tok::l_brace << NewLine;
203+
204+
OS << NameCharRange.str() << Space;
205+
OS << tok::equal << Space;
206+
OS << ElseCharRange.str() << NewLine;
207+
208+
OS << tok::r_brace;
209+
210+
// Start replacement with name range, skip the specifier
211+
auto ReplaceRange(NameCharRange);
212+
ReplaceRange.widen(IfCharRange);
213+
214+
EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());
215+
216+
return false; // don't abort
217+
}

0 commit comments

Comments
 (0)