Skip to content

Commit 713dcd8

Browse files
committed
Expand Memberwise Initializer Refactoring Action
- Struct declarations are now eligible for the refactoring action - Default argument expressions specified in source are printed into the generated initializer as well Note that we are explicitly missing the ability to print a 'nil' default argument for members of type T? because TypeReprs are not fully resolved by the time the refactoring engine runs.
1 parent 6ddfd15 commit 713dcd8

File tree

1 file changed

+83
-61
lines changed

1 file changed

+83
-61
lines changed

lib/IDE/Refactoring.cpp

Lines changed: 83 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2752,78 +2752,107 @@ bool RefactoringActionLocalizeString::performChange() {
27522752
return false;
27532753
}
27542754

2755+
struct MemberwiseParameter {
2756+
Identifier Name;
2757+
Type MemberType;
2758+
Expr *DefaultExpr;
2759+
2760+
MemberwiseParameter(Identifier name, Type type, Expr *initialExpr)
2761+
: Name(name), MemberType(type), DefaultExpr(initialExpr) {}
2762+
};
2763+
27552764
static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
2756-
SourceManager &SM,
2757-
SmallVectorImpl<std::string>& memberNameVector,
2758-
SmallVectorImpl<std::string>& memberTypeVector,
2759-
SourceLoc targetLocation) {
2760-
2761-
assert(!memberTypeVector.empty());
2762-
assert(memberTypeVector.size() == memberNameVector.size());
2765+
SourceManager &SM,
2766+
ArrayRef<MemberwiseParameter> memberVector,
2767+
SourceLoc targetLocation) {
27632768

2769+
assert(!memberVector.empty());
2770+
27642771
EditConsumer.accept(SM, targetLocation, "\ninternal init(");
2765-
2766-
for (size_t i = 0, n = memberTypeVector.size(); i < n ; i++) {
2767-
EditConsumer.accept(SM, targetLocation, memberNameVector[i] + ": " +
2768-
memberTypeVector[i]);
2769-
2770-
if (i != memberTypeVector.size() - 1) {
2771-
EditConsumer.accept(SM, targetLocation, ", ");
2772+
auto insertMember = [&SM](const MemberwiseParameter &memberData,
2773+
llvm::raw_ostream &OS, bool wantsSeparator) {
2774+
OS << memberData.Name << ": " << memberData.MemberType.getString();
2775+
if (auto *expr = memberData.DefaultExpr) {
2776+
if (isa<NilLiteralExpr>(expr)) {
2777+
OS << " = nil";
2778+
} else if (expr->getSourceRange().isValid()) {
2779+
auto range =
2780+
Lexer::getCharSourceRangeFromSourceRange(
2781+
SM, expr->getSourceRange());
2782+
OS << " = " << SM.extractText(range);
2783+
}
2784+
}
2785+
2786+
if (wantsSeparator) {
2787+
OS << ", ";
27722788
}
2789+
};
2790+
2791+
// Process the initial list of members, inserting commas as appropriate.
2792+
std::string Buffer;
2793+
llvm::raw_string_ostream OS(Buffer);
2794+
for (const auto &memberData : memberVector.drop_back()) {
2795+
insertMember(memberData, OS, /*wantsSeparator*/ true);
27732796
}
2774-
2775-
EditConsumer.accept(SM, targetLocation, ") {\n");
2776-
2777-
for (auto varName: memberNameVector) {
2778-
EditConsumer.accept(SM, targetLocation,
2779-
"self." + varName + " = " + varName + "\n");
2797+
2798+
// Process the last (or perhaps, only) member.
2799+
insertMember(memberVector.back(), OS, /*wantsSeparator*/ false);
2800+
2801+
// Synthesize the body.
2802+
OS << ") {\n";
2803+
for (auto &member : memberVector) {
2804+
// self.<property> = <property>
2805+
OS << "self." << member.Name << " = " << member.Name << "\n";
27802806
}
2781-
2782-
EditConsumer.accept(SM, targetLocation, "}\n");
2807+
OS << "}\n";
2808+
2809+
// Accept the entire edit.
2810+
EditConsumer.accept(SM, targetLocation, OS.str());
27832811
}
2784-
2785-
static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo,
2786-
SmallVectorImpl<std::string>& memberNameVector,
2787-
SmallVectorImpl<std::string>& memberTypeVector) {
2788-
2812+
2813+
static SourceLoc
2814+
collectMembersForInit(ResolvedCursorInfo CursorInfo,
2815+
SmallVectorImpl<MemberwiseParameter> &memberVector) {
2816+
27892817
if (!CursorInfo.ValueD)
27902818
return SourceLoc();
27912819

2792-
ClassDecl *classDecl = dyn_cast<ClassDecl>(CursorInfo.ValueD);
2793-
if (!classDecl || classDecl->getStoredProperties().empty() ||
2820+
NominalTypeDecl *nominalDecl = dyn_cast<NominalTypeDecl>(CursorInfo.ValueD);
2821+
if (!nominalDecl || nominalDecl->getStoredProperties().empty() ||
27942822
CursorInfo.IsRef) {
27952823
return SourceLoc();
27962824
}
2797-
2798-
SourceLoc bracesStart = classDecl->getBraces().Start;
2825+
2826+
SourceLoc bracesStart = nominalDecl->getBraces().Start;
27992827
if (!bracesStart.isValid())
28002828
return SourceLoc();
28012829

28022830
SourceLoc targetLocation = bracesStart.getAdvancedLoc(1);
28032831
if (!targetLocation.isValid())
28042832
return SourceLoc();
2805-
2806-
for (auto varDecl : classDecl->getStoredProperties()) {
2807-
auto parentPatternBinding = varDecl->getParentPatternBinding();
2808-
if (!parentPatternBinding)
2833+
2834+
for (auto varDecl : nominalDecl->getStoredProperties()) {
2835+
auto patternBinding = varDecl->getParentPatternBinding();
2836+
if (!patternBinding)
2837+
continue;
2838+
2839+
if (!varDecl->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) {
28092840
continue;
2810-
2811-
auto varDeclIndex =
2812-
parentPatternBinding->getPatternEntryIndexForVarDecl(varDecl);
2813-
2814-
if (auto init = varDecl->getParentPatternBinding()->getInit(varDeclIndex)) {
2815-
if (init->getStartLoc().isValid())
2816-
continue;
28172841
}
2818-
2819-
StringRef memberName = varDecl->getName().str();
2820-
memberNameVector.push_back(memberName.str());
2821-
2822-
std::string memberType = varDecl->getType().getString();
2823-
memberTypeVector.push_back(memberType);
2842+
2843+
auto &entry = patternBinding->getPatternEntryForVarDecl(varDecl);
2844+
bool isExplicitlyInitialized =
2845+
entry.isInitialized() && entry.getEqualLoc().isValid();
2846+
Expr *defaultInit = nullptr;
2847+
if (isExplicitlyInitialized || patternBinding->isDefaultInitializable()) {
2848+
defaultInit = varDecl->getParentInitializer();
2849+
}
2850+
2851+
memberVector.emplace_back(varDecl->getName(),
2852+
varDecl->getType(), defaultInit);
28242853
}
28252854

2826-
if (memberNameVector.empty() || memberTypeVector.empty()) {
2855+
if (memberVector.empty()) {
28272856
return SourceLoc();
28282857
}
28292858

@@ -2833,25 +2862,18 @@ static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo,
28332862
bool RefactoringActionMemberwiseInitLocalRefactoring::
28342863
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
28352864

2836-
SmallVector<std::string, 8> memberNameVector;
2837-
SmallVector<std::string, 8> memberTypeVector;
2838-
2839-
return collectMembersForInit(Tok, memberNameVector,
2840-
memberTypeVector).isValid();
2865+
SmallVector<MemberwiseParameter, 8> memberVector;
2866+
return collectMembersForInit(Tok, memberVector).isValid();
28412867
}
28422868

28432869
bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() {
28442870

2845-
SmallVector<std::string, 8> memberNameVector;
2846-
SmallVector<std::string, 8> memberTypeVector;
2847-
2848-
SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberNameVector,
2849-
memberTypeVector);
2871+
SmallVector<MemberwiseParameter, 8> memberVector;
2872+
SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector);
28502873
if (targetLocation.isInvalid())
28512874
return true;
28522875

2853-
generateMemberwiseInit(EditConsumer, SM, memberNameVector,
2854-
memberTypeVector, targetLocation);
2876+
generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation);
28552877

28562878
return false;
28572879
}

0 commit comments

Comments
 (0)