Skip to content

Commit b52a092

Browse files
committed
SR-5741 Refactoring action to convert from field initialization to computed property
1 parent e1e7a3f commit b52a092

File tree

15 files changed

+456
-4
lines changed

15 files changed

+456
-4
lines changed

include/swift/IDE/RefactoringKinds.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ RANGE_REFACTORING(ConvertIfLetExprToGuardExpr, "Convert To Guard Expression", co
7070

7171
RANGE_REFACTORING(ConvertGuardExprToIfLetExpr, "Convert To IfLet Expression", convert.to.iflet.expr)
7272

73+
RANGE_REFACTORING(ConvertToComputedProperty, "Convert To Computed Property", convert.to.computed.property)
74+
7375
// These internal refactorings are designed to be helpful for working on
7476
// the compiler/standard library, etc., but are likely to be just confusing and
7577
// noise for general development.

lib/IDE/Refactoring.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3166,6 +3166,97 @@ static bool rangeStartMayNeedRename(ResolvedRangeInfo Info) {
31663166
}
31673167
llvm_unreachable("unhandled kind");
31683168
}
3169+
3170+
bool RefactoringActionConvertToComputedProperty::
3171+
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
3172+
if (Info.Kind != RangeKind::SingleDecl) {
3173+
return false;
3174+
}
3175+
3176+
if (Info.ContainedNodes.size() != 1) {
3177+
return false;
3178+
}
3179+
3180+
auto D = Info.ContainedNodes[0].dyn_cast<Decl*>();
3181+
if (!D) {
3182+
return false;
3183+
}
3184+
3185+
auto Binding = dyn_cast<PatternBindingDecl>(D);
3186+
if (!Binding) {
3187+
return false;
3188+
}
3189+
3190+
auto SV = Binding->getSingleVar();
3191+
if (!SV) {
3192+
return false;
3193+
}
3194+
3195+
// willSet, didSet cannot be provided together with a getter
3196+
for (auto AD : SV->getAllAccessors()) {
3197+
if (AD->isObservingAccessor()) {
3198+
return false;
3199+
}
3200+
}
3201+
3202+
// 'lazy' must not be used on a computed property
3203+
// NSCopying and IBOutlet attribute requires property to be mutable
3204+
auto Attributies = SV->getAttrs();
3205+
if (Attributies.hasAttribute<LazyAttr>() ||
3206+
Attributies.hasAttribute<NSCopyingAttr>() ||
3207+
Attributies.hasAttribute<IBOutletAttr>()) {
3208+
return false;
3209+
}
3210+
3211+
// Property wrapper cannot be applied to a computed property
3212+
if (SV->hasAttachedPropertyWrapper()) {
3213+
return false;
3214+
}
3215+
3216+
// has an initializer
3217+
return Binding->hasInitStringRepresentation(0);
3218+
}
3219+
3220+
bool RefactoringActionConvertToComputedProperty::performChange() {
3221+
// Get an initialization
3222+
auto D = RangeInfo.ContainedNodes[0].dyn_cast<Decl*>();
3223+
auto Binding = dyn_cast<PatternBindingDecl>(D);
3224+
SmallString<128> scratch;
3225+
auto Init = Binding->getInitStringRepresentation(0, scratch);
3226+
3227+
// Get type
3228+
auto SV = Binding->getSingleVar();
3229+
auto SVType = SV->getType();
3230+
auto TR = SV->getTypeReprOrParentPatternTypeRepr();
3231+
3232+
llvm::SmallString<64> DeclBuffer;
3233+
llvm::raw_svector_ostream OS(DeclBuffer);
3234+
llvm::StringRef Space = " ";
3235+
llvm::StringRef NewLine = "\n";
3236+
3237+
OS << tok::kw_var << Space;
3238+
// Add var name
3239+
OS << SV->getNameStr().str() << ":" << Space;
3240+
// For computed property must write a type of var
3241+
if (TR) {
3242+
OS << Lexer::getCharSourceRangeFromSourceRange(SM, TR->getSourceRange()).str();
3243+
} else {
3244+
SVType.print(OS);
3245+
}
3246+
3247+
OS << Space << tok::l_brace << NewLine;
3248+
// Add an initialization
3249+
OS << tok::kw_return << Space << Init.str() << NewLine;
3250+
OS << tok::r_brace;
3251+
3252+
// Replace initializer to computed property
3253+
auto ReplaceStartLoc = Binding->getLoc();
3254+
auto ReplaceEndLoc = Binding->getSourceRange().End;
3255+
auto ReplaceRange = SourceRange(ReplaceStartLoc, ReplaceEndLoc);
3256+
auto ReplaceCharSourceRange = Lexer::getCharSourceRangeFromSourceRange(SM, ReplaceRange);
3257+
EditConsumer.accept(SM, ReplaceCharSourceRange, DeclBuffer.str());
3258+
return false; // success
3259+
}
31693260
}// end of anonymous namespace
31703261

31713262
StringRef swift::ide::
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4 = 4
6+
var y: Int! = 45
7+
}
8+
9+
class C {
10+
static var field1: S {
11+
return S()
12+
}
13+
public var field2 = 2
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4 = 4
6+
var y: Int! = 45
7+
}
8+
9+
class C {
10+
static var field1 = S()
11+
public var field2: Int {
12+
return 2
13+
}
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4 = 4
6+
var y: Int! = 45
7+
}
8+
9+
class C {
10+
static var field1 = S()
11+
public var field2 = 2
12+
private dynamic var field3: Int {
13+
return 5
14+
}
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4 = 4
6+
var y: Int! = 45
7+
}
8+
9+
class C {
10+
static var field1 = S()
11+
public var field2 = 2
12+
private dynamic var field3 = 5
13+
@available(macOS 10.12, *) private static dynamic var field4: Int {
14+
return 4
15+
}
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4 = 4
6+
var y: Int! = 45
7+
}
8+
9+
class C {
10+
static var field1 = S()
11+
public var field2 = 2
12+
private dynamic var field3 = 5
13+
@available(macOS 10.12, *) private static dynamic var field4 = 4
14+
var field5: Int {
15+
return 5
16+
}
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1: Int {
3+
return 2
4+
}
5+
var field2 = "2"
6+
var field3 = String()
7+
static var field4 = 4
8+
var y: Int! = 45
9+
}
10+
11+
class C {
12+
static var field1 = S()
13+
public var field2 = 2
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2: String {
4+
return "2"
5+
}
6+
var field3 = String()
7+
static var field4 = 4
8+
var y: Int! = 45
9+
}
10+
11+
class C {
12+
static var field1 = S()
13+
public var field2 = 2
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3: String {
5+
return String()
6+
}
7+
static var field4 = 4
8+
var y: Int! = 45
9+
}
10+
11+
class C {
12+
static var field1 = S()
13+
public var field2 = 2
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4: Int {
6+
return 4
7+
}
8+
var y: Int! = 45
9+
}
10+
11+
class C {
12+
static var field1 = S()
13+
public var field2 = 2
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
struct S {
2+
var field1 = 2
3+
var field2 = "2"
4+
var field3 = String()
5+
static var field4 = 4
6+
var y: Int! {
7+
return 45
8+
}
9+
}
10+
11+
class C {
12+
static var field1 = S()
13+
public var field2 = 2
14+
private dynamic var field3 = 5
15+
@available(macOS 10.12, *) private static dynamic var field4 = 4
16+
let field5 = 5
17+
}
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+

0 commit comments

Comments
 (0)