Skip to content

Commit a48d0f2

Browse files
committed
[Refactoring] Move MemberwiseInitLocalRefactoring to its own file
1 parent 7e87813 commit a48d0f2

File tree

3 files changed

+160
-142
lines changed

3 files changed

+160
-142
lines changed

lib/Refactoring/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_swift_host_library(swiftRefactoring STATIC
1313
ExtractFunction.cpp
1414
FillProtocolStubs.cpp
1515
LocalizeString.cpp
16+
MemberwiseInitLocalRefactoring.cpp
1617
MoveMembersToExtension.cpp
1718
Refactoring.cpp
1819
Renamer.cpp
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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+
15+
using namespace swift::refactoring;
16+
17+
namespace {
18+
struct MemberwiseParameter {
19+
CharSourceRange NameRange;
20+
Type MemberType;
21+
Expr *DefaultExpr;
22+
23+
MemberwiseParameter(CharSourceRange nameRange, Type type, Expr *initialExpr)
24+
: NameRange(nameRange), MemberType(type), DefaultExpr(initialExpr) {}
25+
};
26+
} // namespace
27+
28+
static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
29+
SourceManager &SM,
30+
ArrayRef<MemberwiseParameter> memberVector,
31+
SourceLoc targetLocation) {
32+
33+
EditConsumer.accept(SM, targetLocation, "\ninternal init(");
34+
auto insertMember = [&SM](const MemberwiseParameter &memberData,
35+
raw_ostream &OS, bool wantsSeparator) {
36+
{
37+
OS << SM.extractText(memberData.NameRange) << ": ";
38+
// Unconditionally print '@escaping' if we print out a function type -
39+
// the assignments we generate below will escape this parameter.
40+
if (isa<AnyFunctionType>(memberData.MemberType->getCanonicalType())) {
41+
OS << "@" << TypeAttributes::getAttrName(TAK_escaping) << " ";
42+
}
43+
OS << memberData.MemberType.getString();
44+
}
45+
46+
bool HasAddedDefault = false;
47+
if (auto *expr = memberData.DefaultExpr) {
48+
if (expr->getSourceRange().isValid()) {
49+
auto range = Lexer::getCharSourceRangeFromSourceRange(
50+
SM, expr->getSourceRange());
51+
OS << " = " << SM.extractText(range);
52+
HasAddedDefault = true;
53+
}
54+
}
55+
if (!HasAddedDefault && memberData.MemberType->isOptional()) {
56+
OS << " = nil";
57+
}
58+
59+
if (wantsSeparator) {
60+
OS << ", ";
61+
}
62+
};
63+
64+
// Process the initial list of members, inserting commas as appropriate.
65+
std::string Buffer;
66+
llvm::raw_string_ostream OS(Buffer);
67+
for (const auto &memberData : llvm::enumerate(memberVector)) {
68+
bool wantsSeparator = (memberData.index() != memberVector.size() - 1);
69+
insertMember(memberData.value(), OS, wantsSeparator);
70+
}
71+
72+
// Synthesize the body.
73+
OS << ") {\n";
74+
for (auto &member : memberVector) {
75+
// self.<property> = <property>
76+
auto name = SM.extractText(member.NameRange);
77+
OS << "self." << name << " = " << name << "\n";
78+
}
79+
OS << "}\n";
80+
81+
// Accept the entire edit.
82+
EditConsumer.accept(SM, targetLocation, OS.str());
83+
}
84+
85+
static SourceLoc
86+
collectMembersForInit(ResolvedCursorInfoPtr CursorInfo,
87+
SmallVectorImpl<MemberwiseParameter> &memberVector) {
88+
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
89+
if (!ValueRefInfo || !ValueRefInfo->getValueD())
90+
return SourceLoc();
91+
92+
NominalTypeDecl *nominalDecl =
93+
dyn_cast<NominalTypeDecl>(ValueRefInfo->getValueD());
94+
if (!nominalDecl || nominalDecl->getStoredProperties().empty() ||
95+
ValueRefInfo->isRef()) {
96+
return SourceLoc();
97+
}
98+
99+
SourceLoc bracesStart = nominalDecl->getBraces().Start;
100+
if (!bracesStart.isValid())
101+
return SourceLoc();
102+
103+
SourceLoc targetLocation = bracesStart.getAdvancedLoc(1);
104+
if (!targetLocation.isValid())
105+
return SourceLoc();
106+
107+
SourceManager &SM = nominalDecl->getASTContext().SourceMgr;
108+
109+
for (auto member : nominalDecl->getMemberwiseInitProperties()) {
110+
auto varDecl = dyn_cast<VarDecl>(member);
111+
if (!varDecl) {
112+
continue;
113+
}
114+
if (varDecl->getAttrs().hasAttribute<LazyAttr>()) {
115+
// Exclude lazy members from the memberwise initializer. This is
116+
// inconsistent with the implicitly synthesized memberwise initializer but
117+
// we think it makes more sense because otherwise the lazy variable's
118+
// initializer gets evaluated eagerly.
119+
continue;
120+
}
121+
122+
auto patternBinding = varDecl->getParentPatternBinding();
123+
if (!patternBinding)
124+
continue;
125+
126+
const auto i = patternBinding->getPatternEntryIndexForVarDecl(varDecl);
127+
Expr *defaultInit = nullptr;
128+
if (patternBinding->isExplicitlyInitialized(i) ||
129+
patternBinding->isDefaultInitializable()) {
130+
defaultInit = patternBinding->getOriginalInit(i);
131+
}
132+
133+
auto NameRange =
134+
Lexer::getCharSourceRangeFromSourceRange(SM, varDecl->getNameLoc());
135+
memberVector.emplace_back(NameRange, varDecl->getTypeInContext(),
136+
defaultInit);
137+
}
138+
139+
return targetLocation;
140+
}
141+
142+
bool RefactoringActionMemberwiseInitLocalRefactoring::isApplicable(
143+
ResolvedCursorInfoPtr Tok, DiagnosticEngine &Diag) {
144+
145+
SmallVector<MemberwiseParameter, 8> memberVector;
146+
return collectMembersForInit(Tok, memberVector).isValid();
147+
}
148+
149+
bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() {
150+
151+
SmallVector<MemberwiseParameter, 8> memberVector;
152+
SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector);
153+
if (targetLocation.isInvalid())
154+
return true;
155+
156+
generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation);
157+
158+
return false;
159+
}

lib/Refactoring/Refactoring.cpp

Lines changed: 0 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -566,148 +566,6 @@ collectRefactoringsAtCursor(SourceFile *SF, unsigned Line, unsigned Column,
566566
return collectRefactorings(Tok, /*ExcludeRename=*/false);
567567
}
568568

569-
struct MemberwiseParameter {
570-
CharSourceRange NameRange;
571-
Type MemberType;
572-
Expr *DefaultExpr;
573-
574-
MemberwiseParameter(CharSourceRange nameRange, Type type, Expr *initialExpr)
575-
: NameRange(nameRange), MemberType(type), DefaultExpr(initialExpr) {}
576-
};
577-
578-
static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
579-
SourceManager &SM,
580-
ArrayRef<MemberwiseParameter> memberVector,
581-
SourceLoc targetLocation) {
582-
583-
EditConsumer.accept(SM, targetLocation, "\ninternal init(");
584-
auto insertMember = [&SM](const MemberwiseParameter &memberData,
585-
raw_ostream &OS, bool wantsSeparator) {
586-
{
587-
OS << SM.extractText(memberData.NameRange) << ": ";
588-
// Unconditionally print '@escaping' if we print out a function type -
589-
// the assignments we generate below will escape this parameter.
590-
if (isa<AnyFunctionType>(memberData.MemberType->getCanonicalType())) {
591-
OS << "@" << TypeAttributes::getAttrName(TAK_escaping) << " ";
592-
}
593-
OS << memberData.MemberType.getString();
594-
}
595-
596-
bool HasAddedDefault = false;
597-
if (auto *expr = memberData.DefaultExpr) {
598-
if (expr->getSourceRange().isValid()) {
599-
auto range =
600-
Lexer::getCharSourceRangeFromSourceRange(
601-
SM, expr->getSourceRange());
602-
OS << " = " << SM.extractText(range);
603-
HasAddedDefault = true;
604-
}
605-
}
606-
if (!HasAddedDefault && memberData.MemberType->isOptional()) {
607-
OS << " = nil";
608-
}
609-
610-
if (wantsSeparator) {
611-
OS << ", ";
612-
}
613-
};
614-
615-
// Process the initial list of members, inserting commas as appropriate.
616-
std::string Buffer;
617-
llvm::raw_string_ostream OS(Buffer);
618-
for (const auto &memberData : llvm::enumerate(memberVector)) {
619-
bool wantsSeparator = (memberData.index() != memberVector.size() - 1);
620-
insertMember(memberData.value(), OS, wantsSeparator);
621-
}
622-
623-
// Synthesize the body.
624-
OS << ") {\n";
625-
for (auto &member : memberVector) {
626-
// self.<property> = <property>
627-
auto name = SM.extractText(member.NameRange);
628-
OS << "self." << name << " = " << name << "\n";
629-
}
630-
OS << "}\n";
631-
632-
// Accept the entire edit.
633-
EditConsumer.accept(SM, targetLocation, OS.str());
634-
}
635-
636-
static SourceLoc
637-
collectMembersForInit(ResolvedCursorInfoPtr CursorInfo,
638-
SmallVectorImpl<MemberwiseParameter> &memberVector) {
639-
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
640-
if (!ValueRefInfo || !ValueRefInfo->getValueD())
641-
return SourceLoc();
642-
643-
NominalTypeDecl *nominalDecl =
644-
dyn_cast<NominalTypeDecl>(ValueRefInfo->getValueD());
645-
if (!nominalDecl || nominalDecl->getStoredProperties().empty() ||
646-
ValueRefInfo->isRef()) {
647-
return SourceLoc();
648-
}
649-
650-
SourceLoc bracesStart = nominalDecl->getBraces().Start;
651-
if (!bracesStart.isValid())
652-
return SourceLoc();
653-
654-
SourceLoc targetLocation = bracesStart.getAdvancedLoc(1);
655-
if (!targetLocation.isValid())
656-
return SourceLoc();
657-
658-
SourceManager &SM = nominalDecl->getASTContext().SourceMgr;
659-
660-
for (auto member : nominalDecl->getMemberwiseInitProperties()) {
661-
auto varDecl = dyn_cast<VarDecl>(member);
662-
if (!varDecl) {
663-
continue;
664-
}
665-
if (varDecl->getAttrs().hasAttribute<LazyAttr>()) {
666-
// Exclude lazy members from the memberwise initializer. This is
667-
// inconsistent with the implicitly synthesized memberwise initializer but
668-
// we think it makes more sense because otherwise the lazy variable's
669-
// initializer gets evaluated eagerly.
670-
continue;
671-
}
672-
673-
auto patternBinding = varDecl->getParentPatternBinding();
674-
if (!patternBinding)
675-
continue;
676-
677-
const auto i = patternBinding->getPatternEntryIndexForVarDecl(varDecl);
678-
Expr *defaultInit = nullptr;
679-
if (patternBinding->isExplicitlyInitialized(i) ||
680-
patternBinding->isDefaultInitializable()) {
681-
defaultInit = patternBinding->getOriginalInit(i);
682-
}
683-
684-
auto NameRange =
685-
Lexer::getCharSourceRangeFromSourceRange(SM, varDecl->getNameLoc());
686-
memberVector.emplace_back(NameRange, varDecl->getTypeInContext(), defaultInit);
687-
}
688-
689-
return targetLocation;
690-
}
691-
692-
bool RefactoringActionMemberwiseInitLocalRefactoring::isApplicable(
693-
ResolvedCursorInfoPtr Tok, DiagnosticEngine &Diag) {
694-
695-
SmallVector<MemberwiseParameter, 8> memberVector;
696-
return collectMembersForInit(Tok, memberVector).isValid();
697-
}
698-
699-
bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() {
700-
701-
SmallVector<MemberwiseParameter, 8> memberVector;
702-
SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector);
703-
if (targetLocation.isInvalid())
704-
return true;
705-
706-
generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation);
707-
708-
return false;
709-
}
710-
711569
/// If \p NTD is a protocol, return all the protocols it inherits from. If it's
712570
/// a type, return all the protocols it conforms to.
713571
static SmallVector<ProtocolDecl *, 2> getAllProtocols(NominalTypeDecl *NTD) {

0 commit comments

Comments
 (0)