mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge remote-tracking branch 'origin/master' into master-next
This commit is contained in:
@@ -2753,78 +2753,107 @@ bool RefactoringActionLocalizeString::performChange() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MemberwiseParameter {
|
||||||
|
Identifier Name;
|
||||||
|
Type MemberType;
|
||||||
|
Expr *DefaultExpr;
|
||||||
|
|
||||||
|
MemberwiseParameter(Identifier name, Type type, Expr *initialExpr)
|
||||||
|
: Name(name), MemberType(type), DefaultExpr(initialExpr) {}
|
||||||
|
};
|
||||||
|
|
||||||
static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
|
static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
|
||||||
SourceManager &SM,
|
SourceManager &SM,
|
||||||
SmallVectorImpl<std::string>& memberNameVector,
|
ArrayRef<MemberwiseParameter> memberVector,
|
||||||
SmallVectorImpl<std::string>& memberTypeVector,
|
SourceLoc targetLocation) {
|
||||||
SourceLoc targetLocation) {
|
|
||||||
|
|
||||||
assert(!memberTypeVector.empty());
|
|
||||||
assert(memberTypeVector.size() == memberNameVector.size());
|
|
||||||
|
|
||||||
|
assert(!memberVector.empty());
|
||||||
|
|
||||||
EditConsumer.accept(SM, targetLocation, "\ninternal init(");
|
EditConsumer.accept(SM, targetLocation, "\ninternal init(");
|
||||||
|
auto insertMember = [&SM](const MemberwiseParameter &memberData,
|
||||||
for (size_t i = 0, n = memberTypeVector.size(); i < n ; i++) {
|
llvm::raw_ostream &OS, bool wantsSeparator) {
|
||||||
EditConsumer.accept(SM, targetLocation, memberNameVector[i] + ": " +
|
OS << memberData.Name << ": " << memberData.MemberType.getString();
|
||||||
memberTypeVector[i]);
|
if (auto *expr = memberData.DefaultExpr) {
|
||||||
|
if (isa<NilLiteralExpr>(expr)) {
|
||||||
if (i != memberTypeVector.size() - 1) {
|
OS << " = nil";
|
||||||
EditConsumer.accept(SM, targetLocation, ", ");
|
} else if (expr->getSourceRange().isValid()) {
|
||||||
|
auto range =
|
||||||
|
Lexer::getCharSourceRangeFromSourceRange(
|
||||||
|
SM, expr->getSourceRange());
|
||||||
|
OS << " = " << SM.extractText(range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wantsSeparator) {
|
||||||
|
OS << ", ";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process the initial list of members, inserting commas as appropriate.
|
||||||
|
std::string Buffer;
|
||||||
|
llvm::raw_string_ostream OS(Buffer);
|
||||||
|
for (const auto &memberData : memberVector.drop_back()) {
|
||||||
|
insertMember(memberData, OS, /*wantsSeparator*/ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditConsumer.accept(SM, targetLocation, ") {\n");
|
// Process the last (or perhaps, only) member.
|
||||||
|
insertMember(memberVector.back(), OS, /*wantsSeparator*/ false);
|
||||||
for (auto varName: memberNameVector) {
|
|
||||||
EditConsumer.accept(SM, targetLocation,
|
// Synthesize the body.
|
||||||
"self." + varName + " = " + varName + "\n");
|
OS << ") {\n";
|
||||||
|
for (auto &member : memberVector) {
|
||||||
|
// self.<property> = <property>
|
||||||
|
OS << "self." << member.Name << " = " << member.Name << "\n";
|
||||||
}
|
}
|
||||||
|
OS << "}\n";
|
||||||
EditConsumer.accept(SM, targetLocation, "}\n");
|
|
||||||
|
// Accept the entire edit.
|
||||||
|
EditConsumer.accept(SM, targetLocation, OS.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo,
|
static SourceLoc
|
||||||
SmallVectorImpl<std::string>& memberNameVector,
|
collectMembersForInit(ResolvedCursorInfo CursorInfo,
|
||||||
SmallVectorImpl<std::string>& memberTypeVector) {
|
SmallVectorImpl<MemberwiseParameter> &memberVector) {
|
||||||
|
|
||||||
if (!CursorInfo.ValueD)
|
if (!CursorInfo.ValueD)
|
||||||
return SourceLoc();
|
return SourceLoc();
|
||||||
|
|
||||||
ClassDecl *classDecl = dyn_cast<ClassDecl>(CursorInfo.ValueD);
|
NominalTypeDecl *nominalDecl = dyn_cast<NominalTypeDecl>(CursorInfo.ValueD);
|
||||||
if (!classDecl || classDecl->getStoredProperties().empty() ||
|
if (!nominalDecl || nominalDecl->getStoredProperties().empty() ||
|
||||||
CursorInfo.IsRef) {
|
CursorInfo.IsRef) {
|
||||||
return SourceLoc();
|
return SourceLoc();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLoc bracesStart = classDecl->getBraces().Start;
|
SourceLoc bracesStart = nominalDecl->getBraces().Start;
|
||||||
if (!bracesStart.isValid())
|
if (!bracesStart.isValid())
|
||||||
return SourceLoc();
|
return SourceLoc();
|
||||||
|
|
||||||
SourceLoc targetLocation = bracesStart.getAdvancedLoc(1);
|
SourceLoc targetLocation = bracesStart.getAdvancedLoc(1);
|
||||||
if (!targetLocation.isValid())
|
if (!targetLocation.isValid())
|
||||||
return SourceLoc();
|
return SourceLoc();
|
||||||
|
|
||||||
for (auto varDecl : classDecl->getStoredProperties()) {
|
for (auto varDecl : nominalDecl->getStoredProperties()) {
|
||||||
auto parentPatternBinding = varDecl->getParentPatternBinding();
|
auto patternBinding = varDecl->getParentPatternBinding();
|
||||||
if (!parentPatternBinding)
|
if (!patternBinding)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!varDecl->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto varDeclIndex =
|
|
||||||
parentPatternBinding->getPatternEntryIndexForVarDecl(varDecl);
|
|
||||||
|
|
||||||
if (auto init = varDecl->getParentPatternBinding()->getInit(varDeclIndex)) {
|
|
||||||
if (init->getStartLoc().isValid())
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef memberName = varDecl->getName().str();
|
auto &entry = patternBinding->getPatternEntryForVarDecl(varDecl);
|
||||||
memberNameVector.push_back(memberName.str());
|
bool isExplicitlyInitialized =
|
||||||
|
entry.isInitialized() && entry.getEqualLoc().isValid();
|
||||||
std::string memberType = varDecl->getType().getString();
|
Expr *defaultInit = nullptr;
|
||||||
memberTypeVector.push_back(memberType);
|
if (isExplicitlyInitialized || patternBinding->isDefaultInitializable()) {
|
||||||
|
defaultInit = varDecl->getParentInitializer();
|
||||||
|
}
|
||||||
|
|
||||||
|
memberVector.emplace_back(varDecl->getName(),
|
||||||
|
varDecl->getType(), defaultInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memberNameVector.empty() || memberTypeVector.empty()) {
|
if (memberVector.empty()) {
|
||||||
return SourceLoc();
|
return SourceLoc();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2834,25 +2863,18 @@ static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo,
|
|||||||
bool RefactoringActionMemberwiseInitLocalRefactoring::
|
bool RefactoringActionMemberwiseInitLocalRefactoring::
|
||||||
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
|
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
|
||||||
|
|
||||||
SmallVector<std::string, 8> memberNameVector;
|
SmallVector<MemberwiseParameter, 8> memberVector;
|
||||||
SmallVector<std::string, 8> memberTypeVector;
|
return collectMembersForInit(Tok, memberVector).isValid();
|
||||||
|
|
||||||
return collectMembersForInit(Tok, memberNameVector,
|
|
||||||
memberTypeVector).isValid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() {
|
bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() {
|
||||||
|
|
||||||
SmallVector<std::string, 8> memberNameVector;
|
SmallVector<MemberwiseParameter, 8> memberVector;
|
||||||
SmallVector<std::string, 8> memberTypeVector;
|
SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector);
|
||||||
|
|
||||||
SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberNameVector,
|
|
||||||
memberTypeVector);
|
|
||||||
if (targetLocation.isInvalid())
|
if (targetLocation.isInvalid())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
generateMemberwiseInit(EditConsumer, SM, memberNameVector,
|
generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation);
|
||||||
memberTypeVector, targetLocation);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -759,6 +759,26 @@ IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs,
|
|||||||
IgnoreContextualType(cs, resultTy, specifiedTy, locator);
|
IgnoreContextualType(cs, resultTy, specifiedTy, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IgnoreAssignmentDestinationType::diagnose(Expr *root, bool asNote) const {
|
||||||
|
auto &cs = getConstraintSystem();
|
||||||
|
auto *AE = cast<AssignExpr>(getAnchor());
|
||||||
|
auto CTP = isa<SubscriptExpr>(AE->getDest()) ? CTP_SubscriptAssignSource
|
||||||
|
: CTP_AssignSource;
|
||||||
|
|
||||||
|
ContextualFailure failure(
|
||||||
|
root, cs, CTP, getFromType(), getToType(),
|
||||||
|
cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType()));
|
||||||
|
return failure.diagnose(asNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
IgnoreAssignmentDestinationType *
|
||||||
|
IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy,
|
||||||
|
Type destTy,
|
||||||
|
ConstraintLocator *locator) {
|
||||||
|
return new (cs.getAllocator())
|
||||||
|
IgnoreAssignmentDestinationType(cs, sourceTy, destTy, locator);
|
||||||
|
}
|
||||||
|
|
||||||
bool AllowInOutConversion::diagnose(Expr *root, bool asNote) const {
|
bool AllowInOutConversion::diagnose(Expr *root, bool asNote) const {
|
||||||
auto &cs = getConstraintSystem();
|
auto &cs = getConstraintSystem();
|
||||||
InOutConversionFailure failure(root, cs, getFromType(), getToType(),
|
InOutConversionFailure failure(root, cs, getFromType(), getToType(),
|
||||||
|
|||||||
@@ -1299,6 +1299,23 @@ public:
|
|||||||
ConstraintLocator *locator);
|
ConstraintLocator *locator);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IgnoreAssignmentDestinationType final : public ContextualMismatch {
|
||||||
|
IgnoreAssignmentDestinationType(ConstraintSystem &cs, Type sourceTy,
|
||||||
|
Type destTy, ConstraintLocator *locator)
|
||||||
|
: ContextualMismatch(cs, sourceTy, destTy, locator) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string getName() const override {
|
||||||
|
return "ignore type of the assignment destination";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool diagnose(Expr *root, bool asNote = false) const override;
|
||||||
|
|
||||||
|
static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs,
|
||||||
|
Type sourceTy, Type destTy,
|
||||||
|
ConstraintLocator *locator);
|
||||||
|
};
|
||||||
|
|
||||||
/// If this is an argument-to-parameter conversion which is associated with
|
/// If this is an argument-to-parameter conversion which is associated with
|
||||||
/// `inout` parameter, subtyping is not permitted, types have to
|
/// `inout` parameter, subtyping is not permitted, types have to
|
||||||
/// be identical.
|
/// be identical.
|
||||||
|
|||||||
@@ -2353,6 +2353,15 @@ bool ConstraintSystem::repairFailures(
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) {
|
||||||
|
return llvm::any_of(conversionsOrFixes,
|
||||||
|
[kind](const RestrictionOrFix correction) {
|
||||||
|
if (auto restriction = correction.getRestriction())
|
||||||
|
return restriction == kind;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
if (!anchor)
|
if (!anchor)
|
||||||
return false;
|
return false;
|
||||||
@@ -2391,20 +2400,39 @@ bool ConstraintSystem::repairFailures(
|
|||||||
|
|
||||||
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
|
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// If we are trying to assign e.g. `Array<Int>` to `Array<Float>` let's
|
||||||
|
// give solver a chance to determine which generic parameters are
|
||||||
|
// mismatched and produce a fix for that.
|
||||||
|
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If the situation has to do with protocol composition types and
|
||||||
|
// destination doesn't have one of the conformances e.g. source is
|
||||||
|
// `X & Y` but destination is only `Y` or vice versa, there is a
|
||||||
|
// tailored "missing conformance" fix for that.
|
||||||
|
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If this is an attempt to assign something to a value of optional type
|
||||||
|
// there is a possiblity that the problem is related to escapiness, so
|
||||||
|
// fix has to be delayed.
|
||||||
|
if (hasConversionOrRestriction(
|
||||||
|
ConversionRestrictionKind::ValueToOptional))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If the destination of an assignment is l-value type
|
||||||
|
// it leaves only possible reason for failure - a type mismatch.
|
||||||
|
if (getType(AE->getDest())->is<LValueType>()) {
|
||||||
|
conversionsOrFixes.push_back(IgnoreAssignmentDestinationType::create(
|
||||||
|
*this, lhs, rhs, getConstraintLocator(locator)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) {
|
|
||||||
return llvm::any_of(conversionsOrFixes,
|
|
||||||
[kind](const RestrictionOrFix correction) {
|
|
||||||
if (auto restriction = correction.getRestriction())
|
|
||||||
return restriction == kind;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
auto elt = path.back();
|
auto elt = path.back();
|
||||||
switch (elt.getKind()) {
|
switch (elt.getKind()) {
|
||||||
case ConstraintLocator::LValueConversion: {
|
case ConstraintLocator::LValueConversion: {
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ func rdar20868864(_ s: String) {
|
|||||||
func r22058555() {
|
func r22058555() {
|
||||||
var firstChar: UInt8 = 0
|
var firstChar: UInt8 = 0
|
||||||
"abc".withCString { chars in
|
"abc".withCString { chars in
|
||||||
firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}}
|
firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} {{17-17=UInt8(}} {{25-25=)}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func useIdentity(_ x: Int, y: Float, i32: Int32) {
|
|||||||
|
|
||||||
// Deduction where the result type and input type can get different results
|
// Deduction where the result type and input type can get different results
|
||||||
var xx : X, yy : Y
|
var xx : X, yy : Y
|
||||||
xx = identity(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}}
|
xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}}
|
||||||
xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}}
|
xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ struct YourFoo: Foo {}
|
|||||||
func someTypeIsTheSame() {
|
func someTypeIsTheSame() {
|
||||||
var a = foo(0)
|
var a = foo(0)
|
||||||
a = foo(0)
|
a = foo(0)
|
||||||
a = foo("") // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
|
a = foo("") // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}}
|
||||||
|
|
||||||
var b = foo("")
|
var b = foo("")
|
||||||
b = foo(0) // expected-error{{cannot convert value of type 'Int' to expected argument type 'String'}}
|
b = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}}
|
||||||
b = foo("")
|
b = foo("")
|
||||||
|
|
||||||
var c = foo(MyFoo())
|
var c = foo(MyFoo())
|
||||||
c = foo(0) // expected-error{{cannot convert value of type 'Int' to expected argument type 'MyFoo'}}
|
c = foo(0) // expected-error{{cannot assign value of type 'some Foo' (result of 'foo') to type 'some Foo' (result of 'foo')}}
|
||||||
c = foo(MyFoo())
|
c = foo(MyFoo())
|
||||||
c = foo(YourFoo()) // expected-error{{cannot convert value of type 'YourFoo' to expected argument type 'MyFoo'}}
|
c = foo(YourFoo()) // expected-error{{cannot convert value of type 'YourFoo' to expected argument type 'MyFoo'}}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
class Person {
|
|
||||||
internal init(firstName: String?, lastName: String?, age: Int?) {
|
|
||||||
self.firstName = firstName
|
|
||||||
self.lastName = lastName
|
|
||||||
self.age = age
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstName: String!
|
|
||||||
var lastName: String!
|
|
||||||
var age: Int!
|
|
||||||
var planet = "Earth", solarSystem = "Milky Way"
|
|
||||||
var avgHeight = 175
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
class Person {
|
||||||
|
internal init(firstName: String? = nil, lastName: String? = nil, age: Int? = nil, planet: String = "Earth", solarSystem: String = "Milky Way", avgHeight: Int = 175) {
|
||||||
|
self.firstName = firstName
|
||||||
|
self.lastName = lastName
|
||||||
|
self.age = age
|
||||||
|
self.planet = planet
|
||||||
|
self.solarSystem = solarSystem
|
||||||
|
self.avgHeight = avgHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstName: String!
|
||||||
|
var lastName: String!
|
||||||
|
var age: Int!
|
||||||
|
var planet = "Earth", solarSystem = "Milky Way"
|
||||||
|
var avgHeight = 175
|
||||||
|
let line = #line, file = #file, handle = #dsohandle
|
||||||
|
lazy var idea: Idea = { fatalError() }()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Place {
|
||||||
|
let person: Person
|
||||||
|
let street: String
|
||||||
|
let apartment: Optional<String>
|
||||||
|
let city: String
|
||||||
|
let state: String
|
||||||
|
let postalCode: Int
|
||||||
|
let plusFour: Int?
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol Thing {
|
||||||
|
var idea: Idea { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Idea {
|
||||||
|
var subject: String { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
class Person {
|
||||||
|
var firstName: String!
|
||||||
|
var lastName: String!
|
||||||
|
var age: Int!
|
||||||
|
var planet = "Earth", solarSystem = "Milky Way"
|
||||||
|
var avgHeight = 175
|
||||||
|
let line = #line, file = #file, handle = #dsohandle
|
||||||
|
lazy var idea: Idea = { fatalError() }()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Place {
|
||||||
|
internal init(person: Person, street: String, apartment: Optional<String>, city: String, state: String, postalCode: Int, plusFour: Int?) {
|
||||||
|
self.person = person
|
||||||
|
self.street = street
|
||||||
|
self.apartment = apartment
|
||||||
|
self.city = city
|
||||||
|
self.state = state
|
||||||
|
self.postalCode = postalCode
|
||||||
|
self.plusFour = plusFour
|
||||||
|
}
|
||||||
|
|
||||||
|
let person: Person
|
||||||
|
let street: String
|
||||||
|
let apartment: Optional<String>
|
||||||
|
let city: String
|
||||||
|
let state: String
|
||||||
|
let postalCode: Int
|
||||||
|
let plusFour: Int?
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol Thing {
|
||||||
|
var idea: Idea { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Idea {
|
||||||
|
var subject: String { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
class Person {
|
|
||||||
var firstName: String!
|
|
||||||
var lastName: String!
|
|
||||||
var age: Int!
|
|
||||||
var planet = "Earth", solarSystem = "Milky Way"
|
|
||||||
var avgHeight = 175
|
|
||||||
}
|
|
||||||
|
|
||||||
// RUN: %empty-directory(%t.result)
|
|
||||||
// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/class_members.swift
|
|
||||||
// RUN: diff -u %S/Outputs/class_members/class_members.swift.expected %t.result/class_members.swift
|
|
||||||
38
test/refactoring/MemberwiseInit/generate_memberwise.swift
Normal file
38
test/refactoring/MemberwiseInit/generate_memberwise.swift
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
class Person {
|
||||||
|
var firstName: String!
|
||||||
|
var lastName: String!
|
||||||
|
var age: Int!
|
||||||
|
var planet = "Earth", solarSystem = "Milky Way"
|
||||||
|
var avgHeight = 175
|
||||||
|
let line = #line, file = #file, handle = #dsohandle
|
||||||
|
lazy var idea: Idea = { fatalError() }()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Place {
|
||||||
|
let person: Person
|
||||||
|
let street: String
|
||||||
|
let apartment: Optional<String>
|
||||||
|
let city: String
|
||||||
|
let state: String
|
||||||
|
let postalCode: Int
|
||||||
|
let plusFour: Int?
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol Thing {
|
||||||
|
var idea: Idea { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Idea {
|
||||||
|
var subject: String { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUN: %empty-directory(%t.result)
|
||||||
|
// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/generate_memberwise.swift
|
||||||
|
// RUN: diff -u %S/Outputs/generate_memberwise/class_members.swift.expected %t.result/generate_memberwise.swift
|
||||||
|
|
||||||
|
// RUN: %refactor -memberwise-init -source-filename %s -pos=11:8 > %t.result/struct_members.swift
|
||||||
|
// RUN: diff -u %S/Outputs/generate_memberwise/struct_members.swift.expected %t.result/struct_members.swift
|
||||||
|
|
||||||
|
// RUN: not %refactor -memberwise-init -source-filename %s -pos=21:10 > %t.result/protocol_members.swift
|
||||||
|
// RUN: not %refactor -memberwise-init -source-filename %s -pos=25:6 > %t.result/enum_members.swift
|
||||||
|
|
||||||
Reference in New Issue
Block a user