Skip to content

Commit acf8082

Browse files
committed
[Refactoring] Add members with property wrappers to generated memberwise init
Generating a memberwise init would skip over properties with property wrappers. Switch the implementation of memberwise init generation closer to the one that generates the implicit memberwise init by also using `getMembers()` instead of `getStoredProperties()`. rdar://89057767
1 parent 2f0ae44 commit acf8082

File tree

4 files changed

+54
-13
lines changed

4 files changed

+54
-13
lines changed

lib/IDE/Refactoring.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3175,16 +3175,19 @@ static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
31753175
OS << memberData.MemberType.getString();
31763176
}
31773177

3178+
bool HasAddedDefault = false;
31783179
if (auto *expr = memberData.DefaultExpr) {
3179-
if (isa<NilLiteralExpr>(expr)) {
3180-
OS << " = nil";
3181-
} else if (expr->getSourceRange().isValid()) {
3180+
if (expr->getSourceRange().isValid()) {
31823181
auto range =
31833182
Lexer::getCharSourceRangeFromSourceRange(
31843183
SM, expr->getSourceRange());
31853184
OS << " = " << SM.extractText(range);
3185+
HasAddedDefault = true;
31863186
}
31873187
}
3188+
if (!HasAddedDefault && memberData.MemberType->isOptional()) {
3189+
OS << " = nil";
3190+
}
31883191

31893192
if (wantsSeparator) {
31903193
OS << ", ";
@@ -3234,26 +3237,38 @@ collectMembersForInit(const ResolvedCursorInfo &CursorInfo,
32343237
if (!targetLocation.isValid())
32353238
return SourceLoc();
32363239

3237-
for (auto varDecl : nominalDecl->getStoredProperties()) {
3238-
auto patternBinding = varDecl->getParentPatternBinding();
3239-
if (!patternBinding)
3240+
for (auto member : nominalDecl->getMembers()) {
3241+
auto varDecl = dyn_cast<VarDecl>(member);
3242+
if (!varDecl) {
32403243
continue;
3244+
}
3245+
if (varDecl->getAttrs().hasAttribute<LazyAttr>()) {
3246+
// Exclude lazy members from the memberwise initializer. This is
3247+
// inconsistent with the implicitly synthesized memberwise initializer but
3248+
// we think it makes more sense because otherwise the lazy variable's
3249+
// initializer gets evaluated eagerly.
3250+
continue;
3251+
}
32413252

32423253
if (!varDecl->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) {
32433254
continue;
32443255
}
32453256

3257+
auto patternBinding = varDecl->getParentPatternBinding();
3258+
if (!patternBinding)
3259+
continue;
3260+
32463261
const auto i = patternBinding->getPatternEntryIndexForVarDecl(varDecl);
32473262
Expr *defaultInit = nullptr;
32483263
if (patternBinding->isExplicitlyInitialized(i) ||
32493264
patternBinding->isDefaultInitializable()) {
3250-
defaultInit = varDecl->getParentInitializer();
3265+
defaultInit = patternBinding->getOriginalInit(i);
32513266
}
32523267

32533268
memberVector.emplace_back(varDecl->getName(),
32543269
varDecl->getType(), defaultInit);
32553270
}
3256-
3271+
32573272
if (memberVector.empty()) {
32583273
return SourceLoc();
32593274
}

test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Person {
2-
internal init(firstName: String? = nil, lastName: String? = nil, age: Int? = nil, planet: String = "Earth", solarSystem: String = "Milky Way", avgHeight: Int = 175, location: @escaping () -> Place = { fatalError() }, secondLocation: (() -> Place)? = nil) {
2+
internal init(firstName: String? = nil, lastName: String? = nil, age: Int? = nil, planet: String = "Earth", solarSystem: String = "Milky Way", avgHeight: Int = 175, location: @escaping () -> Place = { fatalError() }, secondLocation: (() -> Place)? = nil, wrapped: String = "") {
33
self.firstName = firstName
44
self.lastName = lastName
55
self.age = age
@@ -8,6 +8,7 @@ self.solarSystem = solarSystem
88
self.avgHeight = avgHeight
99
self.location = location
1010
self.secondLocation = secondLocation
11+
self.wrapped = wrapped
1112
}
1213

1314
var firstName: String!
@@ -19,6 +20,8 @@ self.secondLocation = secondLocation
1920
lazy var idea: Idea = { fatalError() }()
2021
var location: () -> Place = { fatalError() }
2122
var secondLocation: (() -> Place)!
23+
@MyWrapper var wrapped: String = ""
24+
var computed: String { "hi" }
2225
}
2326

2427
struct Place {
@@ -31,6 +34,7 @@ struct Place {
3134
let postalCode: Int
3235
let plusFour: Int?
3336
let callback: Callback
37+
@MyWrapper var wrapped: String
3438
}
3539

3640
protocol Thing {
@@ -41,6 +45,11 @@ enum Idea {
4145
var subject: String { fatalError() }
4246
}
4347

48+
@propertyWrapper
49+
struct MyWrapper {
50+
let wrappedValue: String
51+
}
52+
4453

4554

4655

test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ class Person {
88
lazy var idea: Idea = { fatalError() }()
99
var location: () -> Place = { fatalError() }
1010
var secondLocation: (() -> Place)!
11+
@MyWrapper var wrapped: String = ""
12+
var computed: String { "hi" }
1113
}
1214

1315
struct Place {
14-
internal init(person: Person, street: String, apartment: Optional<String>, city: String, state: String, postalCode: Int, plusFour: Int?, callback: @escaping Place.Callback) {
16+
internal init(person: Person, street: String, apartment: Optional<String> = nil, city: String, state: String, postalCode: Int, plusFour: Int? = nil, callback: @escaping Place.Callback, wrapped: String) {
1517
self.person = person
1618
self.street = street
1719
self.apartment = apartment
@@ -20,6 +22,7 @@ self.state = state
2022
self.postalCode = postalCode
2123
self.plusFour = plusFour
2224
self.callback = callback
25+
self.wrapped = wrapped
2326
}
2427

2528
typealias Callback = () -> ()
@@ -31,6 +34,7 @@ self.callback = callback
3134
let postalCode: Int
3235
let plusFour: Int?
3336
let callback: Callback
37+
@MyWrapper var wrapped: String
3438
}
3539

3640
protocol Thing {
@@ -41,6 +45,11 @@ enum Idea {
4145
var subject: String { fatalError() }
4246
}
4347

48+
@propertyWrapper
49+
struct MyWrapper {
50+
let wrappedValue: String
51+
}
52+
4453

4554

4655

test/refactoring/MemberwiseInit/generate_memberwise.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class Person {
88
lazy var idea: Idea = { fatalError() }()
99
var location: () -> Place = { fatalError() }
1010
var secondLocation: (() -> Place)!
11+
@MyWrapper var wrapped: String = ""
12+
var computed: String { "hi" }
1113
}
1214

1315
struct Place {
@@ -20,6 +22,7 @@ struct Place {
2022
let postalCode: Int
2123
let plusFour: Int?
2224
let callback: Callback
25+
@MyWrapper var wrapped: String
2326
}
2427

2528
protocol Thing {
@@ -30,13 +33,18 @@ enum Idea {
3033
var subject: String { fatalError() }
3134
}
3235

36+
@propertyWrapper
37+
struct MyWrapper {
38+
let wrappedValue: String
39+
}
40+
3341
// RUN: %empty-directory(%t.result)
3442
// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/generate_memberwise.swift
3543
// RUN: diff -u %S/Outputs/generate_memberwise/class_members.swift.expected %t.result/generate_memberwise.swift
3644

37-
// RUN: %refactor -memberwise-init -source-filename %s -pos=13:8 > %t.result/struct_members.swift
45+
// RUN: %refactor -memberwise-init -source-filename %s -pos=15:8 > %t.result/struct_members.swift
3846
// RUN: diff -u %S/Outputs/generate_memberwise/struct_members.swift.expected %t.result/struct_members.swift
3947

40-
// RUN: not %refactor -memberwise-init -source-filename %s -pos=21:10 > %t.result/protocol_members.swift
41-
// RUN: not %refactor -memberwise-init -source-filename %s -pos=25:6 > %t.result/enum_members.swift
48+
// RUN: not %refactor -memberwise-init -source-filename %s -pos=24:10 > %t.result/protocol_members.swift
49+
// RUN: not %refactor -memberwise-init -source-filename %s -pos=28:6 > %t.result/enum_members.swift
4250

0 commit comments

Comments
 (0)