Skip to content

Commit 1be0c50

Browse files
committed
[Refactoring] Move AddExplicitCodableImplementation to its own file
1 parent fdf2586 commit 1be0c50

File tree

3 files changed

+195
-176
lines changed

3 files changed

+195
-176
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
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+
#include "Utils.h"
15+
16+
using namespace swift::refactoring;
17+
18+
namespace {
19+
class AddCodableContext {
20+
21+
/// Declaration context
22+
DeclContext *DC;
23+
24+
/// Start location of declaration context brace
25+
SourceLoc StartLoc;
26+
27+
/// Array of all conformed protocols
28+
SmallVector<swift::ProtocolDecl *, 2> Protocols;
29+
30+
/// Range of internal members in declaration
31+
DeclRange Range;
32+
33+
bool conformsToCodableProtocol() {
34+
for (ProtocolDecl *Protocol : Protocols) {
35+
if (Protocol->getKnownProtocolKind() == KnownProtocolKind::Encodable ||
36+
Protocol->getKnownProtocolKind() == KnownProtocolKind::Decodable) {
37+
return true;
38+
}
39+
}
40+
return false;
41+
}
42+
43+
public:
44+
AddCodableContext(NominalTypeDecl *Decl)
45+
: DC(Decl), StartLoc(Decl->getBraces().Start),
46+
Protocols(getAllProtocols(Decl)), Range(Decl->getMembers()){};
47+
48+
AddCodableContext(ExtensionDecl *Decl)
49+
: DC(Decl), StartLoc(Decl->getBraces().Start),
50+
Protocols(getAllProtocols(Decl->getExtendedNominal())),
51+
Range(Decl->getMembers()){};
52+
53+
AddCodableContext() : DC(nullptr), Protocols(), Range(nullptr, nullptr){};
54+
55+
static AddCodableContext
56+
getDeclarationContextFromInfo(ResolvedCursorInfoPtr Info);
57+
58+
void printInsertionText(ResolvedCursorInfoPtr CursorInfo, SourceManager &SM,
59+
llvm::raw_ostream &OS);
60+
61+
bool isValid() { return StartLoc.isValid() && conformsToCodableProtocol(); }
62+
63+
SourceLoc getInsertStartLoc();
64+
};
65+
66+
SourceLoc AddCodableContext::getInsertStartLoc() {
67+
SourceLoc MaxLoc = StartLoc;
68+
for (auto Mem : Range) {
69+
if (Mem->getEndLoc().getOpaquePointerValue() >
70+
MaxLoc.getOpaquePointerValue()) {
71+
MaxLoc = Mem->getEndLoc();
72+
}
73+
}
74+
return MaxLoc;
75+
}
76+
77+
/// Walks an AST and prints the synthesized Codable implementation.
78+
class SynthesizedCodablePrinter : public ASTWalker {
79+
private:
80+
ASTPrinter &Printer;
81+
82+
public:
83+
SynthesizedCodablePrinter(ASTPrinter &Printer) : Printer(Printer) {}
84+
85+
MacroWalking getMacroWalkingBehavior() const override {
86+
return MacroWalking::Arguments;
87+
}
88+
89+
PreWalkAction walkToDeclPre(Decl *D) override {
90+
auto *VD = dyn_cast<ValueDecl>(D);
91+
if (!VD)
92+
return Action::SkipChildren();
93+
94+
if (!VD->isSynthesized()) {
95+
return Action::Continue();
96+
}
97+
SmallString<32> Scratch;
98+
auto name = VD->getName().getString(Scratch);
99+
// Print all synthesized enums,
100+
// since Codable can synthesize multiple enums (for associated values).
101+
auto shouldPrint =
102+
isa<EnumDecl>(VD) || name == "init(from:)" || name == "encode(to:)";
103+
if (!shouldPrint) {
104+
// Some other synthesized decl that we don't want to print.
105+
return Action::SkipChildren();
106+
}
107+
108+
Printer.printNewline();
109+
110+
if (auto enumDecl = dyn_cast<EnumDecl>(D)) {
111+
// Manually print enum here, since we don't want to print synthesized
112+
// functions.
113+
Printer << "enum " << enumDecl->getNameStr();
114+
PrintOptions Options;
115+
Options.PrintSpaceBeforeInheritance = false;
116+
enumDecl->printInherited(Printer, Options);
117+
Printer << " {";
118+
for (Decl *EC : enumDecl->getAllElements()) {
119+
Printer.printNewline();
120+
Printer << " ";
121+
EC->print(Printer, Options);
122+
}
123+
Printer.printNewline();
124+
Printer << "}";
125+
return Action::SkipChildren();
126+
}
127+
128+
PrintOptions Options;
129+
Options.SynthesizeSugarOnTypes = true;
130+
Options.FunctionDefinitions = true;
131+
Options.VarInitializers = true;
132+
Options.PrintExprs = true;
133+
Options.TypeDefinitions = true;
134+
Options.ExcludeAttrList.push_back(DAK_HasInitialValue);
135+
136+
Printer.printNewline();
137+
D->print(Printer, Options);
138+
139+
return Action::SkipChildren();
140+
}
141+
};
142+
143+
void AddCodableContext::printInsertionText(ResolvedCursorInfoPtr CursorInfo,
144+
SourceManager &SM,
145+
llvm::raw_ostream &OS) {
146+
StringRef ExtraIndent;
147+
StringRef CurrentIndent =
148+
Lexer::getIndentationForLine(SM, getInsertStartLoc(), &ExtraIndent);
149+
std::string Indent;
150+
if (getInsertStartLoc() == StartLoc) {
151+
Indent = (CurrentIndent + ExtraIndent).str();
152+
} else {
153+
Indent = CurrentIndent.str();
154+
}
155+
156+
ExtraIndentStreamPrinter Printer(OS, Indent);
157+
Printer.printNewline();
158+
SynthesizedCodablePrinter Walker(Printer);
159+
DC->getAsDecl()->walk(Walker);
160+
}
161+
162+
AddCodableContext
163+
AddCodableContext::getDeclarationContextFromInfo(ResolvedCursorInfoPtr Info) {
164+
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(Info);
165+
if (!ValueRefInfo) {
166+
return AddCodableContext();
167+
}
168+
if (!ValueRefInfo->isRef()) {
169+
if (auto *NomDecl = dyn_cast<NominalTypeDecl>(ValueRefInfo->getValueD())) {
170+
return AddCodableContext(NomDecl);
171+
}
172+
}
173+
// TODO: support extensions
174+
// (would need to get synthesized nodes from the main decl,
175+
// and only if it's in the same file?)
176+
return AddCodableContext();
177+
}
178+
} // namespace
179+
180+
bool RefactoringActionAddExplicitCodableImplementation::isApplicable(
181+
ResolvedCursorInfoPtr Tok, DiagnosticEngine &Diag) {
182+
return AddCodableContext::getDeclarationContextFromInfo(Tok).isValid();
183+
}
184+
185+
bool RefactoringActionAddExplicitCodableImplementation::performChange() {
186+
auto Context = AddCodableContext::getDeclarationContextFromInfo(CursorInfo);
187+
188+
SmallString<64> Buffer;
189+
llvm::raw_svector_ostream OS(Buffer);
190+
Context.printInsertionText(CursorInfo, SM, OS);
191+
192+
EditConsumer.insertAfter(SM, Context.getInsertStartLoc(), OS.str());
193+
return false;
194+
}

lib/Refactoring/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_swift_host_library(swiftRefactoring STATIC
22
AddEquatableConformance.cpp
3+
AddExplicitCodableImplementation.cpp
34
CollapseNestedIfStmt.cpp
45
ConvertStringConcatenationToInterpolation.cpp
56
ConvertGuardExprToIfLetExpr.cpp

lib/Refactoring/Refactoring.cpp

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

569-
class AddCodableContext {
570-
571-
/// Declaration context
572-
DeclContext *DC;
573-
574-
/// Start location of declaration context brace
575-
SourceLoc StartLoc;
576-
577-
/// Array of all conformed protocols
578-
SmallVector<swift::ProtocolDecl *, 2> Protocols;
579-
580-
/// Range of internal members in declaration
581-
DeclRange Range;
582-
583-
bool conformsToCodableProtocol() {
584-
for (ProtocolDecl *Protocol : Protocols) {
585-
if (Protocol->getKnownProtocolKind() == KnownProtocolKind::Encodable ||
586-
Protocol->getKnownProtocolKind() == KnownProtocolKind::Decodable) {
587-
return true;
588-
}
589-
}
590-
return false;
591-
}
592-
593-
public:
594-
AddCodableContext(NominalTypeDecl *Decl)
595-
: DC(Decl), StartLoc(Decl->getBraces().Start),
596-
Protocols(getAllProtocols(Decl)), Range(Decl->getMembers()){};
597-
598-
AddCodableContext(ExtensionDecl *Decl)
599-
: DC(Decl), StartLoc(Decl->getBraces().Start),
600-
Protocols(getAllProtocols(Decl->getExtendedNominal())),
601-
Range(Decl->getMembers()){};
602-
603-
AddCodableContext() : DC(nullptr), Protocols(), Range(nullptr, nullptr){};
604-
605-
static AddCodableContext
606-
getDeclarationContextFromInfo(ResolvedCursorInfoPtr Info);
607-
608-
void printInsertionText(ResolvedCursorInfoPtr CursorInfo, SourceManager &SM,
609-
llvm::raw_ostream &OS);
610-
611-
bool isValid() { return StartLoc.isValid() && conformsToCodableProtocol(); }
612-
613-
SourceLoc getInsertStartLoc();
614-
};
615-
616-
SourceLoc AddCodableContext::getInsertStartLoc() {
617-
SourceLoc MaxLoc = StartLoc;
618-
for (auto Mem : Range) {
619-
if (Mem->getEndLoc().getOpaquePointerValue() >
620-
MaxLoc.getOpaquePointerValue()) {
621-
MaxLoc = Mem->getEndLoc();
622-
}
623-
}
624-
return MaxLoc;
625-
}
626-
627-
/// Walks an AST and prints the synthesized Codable implementation.
628-
class SynthesizedCodablePrinter : public ASTWalker {
629-
private:
630-
ASTPrinter &Printer;
631-
632-
public:
633-
SynthesizedCodablePrinter(ASTPrinter &Printer) : Printer(Printer) {}
634-
635-
MacroWalking getMacroWalkingBehavior() const override {
636-
return MacroWalking::Arguments;
637-
}
638-
639-
PreWalkAction walkToDeclPre(Decl *D) override {
640-
auto *VD = dyn_cast<ValueDecl>(D);
641-
if (!VD)
642-
return Action::SkipChildren();
643-
644-
if (!VD->isSynthesized()) {
645-
return Action::Continue();
646-
}
647-
SmallString<32> Scratch;
648-
auto name = VD->getName().getString(Scratch);
649-
// Print all synthesized enums,
650-
// since Codable can synthesize multiple enums (for associated values).
651-
auto shouldPrint =
652-
isa<EnumDecl>(VD) || name == "init(from:)" || name == "encode(to:)";
653-
if (!shouldPrint) {
654-
// Some other synthesized decl that we don't want to print.
655-
return Action::SkipChildren();
656-
}
657-
658-
Printer.printNewline();
659-
660-
if (auto enumDecl = dyn_cast<EnumDecl>(D)) {
661-
// Manually print enum here, since we don't want to print synthesized
662-
// functions.
663-
Printer << "enum " << enumDecl->getNameStr();
664-
PrintOptions Options;
665-
Options.PrintSpaceBeforeInheritance = false;
666-
enumDecl->printInherited(Printer, Options);
667-
Printer << " {";
668-
for (Decl *EC : enumDecl->getAllElements()) {
669-
Printer.printNewline();
670-
Printer << " ";
671-
EC->print(Printer, Options);
672-
}
673-
Printer.printNewline();
674-
Printer << "}";
675-
return Action::SkipChildren();
676-
}
677-
678-
PrintOptions Options;
679-
Options.SynthesizeSugarOnTypes = true;
680-
Options.FunctionDefinitions = true;
681-
Options.VarInitializers = true;
682-
Options.PrintExprs = true;
683-
Options.TypeDefinitions = true;
684-
Options.ExcludeAttrList.push_back(DAK_HasInitialValue);
685-
686-
Printer.printNewline();
687-
D->print(Printer, Options);
688-
689-
return Action::SkipChildren();
690-
}
691-
};
692-
693-
void AddCodableContext::printInsertionText(ResolvedCursorInfoPtr CursorInfo,
694-
SourceManager &SM,
695-
llvm::raw_ostream &OS) {
696-
StringRef ExtraIndent;
697-
StringRef CurrentIndent =
698-
Lexer::getIndentationForLine(SM, getInsertStartLoc(), &ExtraIndent);
699-
std::string Indent;
700-
if (getInsertStartLoc() == StartLoc) {
701-
Indent = (CurrentIndent + ExtraIndent).str();
702-
} else {
703-
Indent = CurrentIndent.str();
704-
}
705-
706-
ExtraIndentStreamPrinter Printer(OS, Indent);
707-
Printer.printNewline();
708-
SynthesizedCodablePrinter Walker(Printer);
709-
DC->getAsDecl()->walk(Walker);
710-
}
711-
712-
AddCodableContext
713-
AddCodableContext::getDeclarationContextFromInfo(ResolvedCursorInfoPtr Info) {
714-
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(Info);
715-
if (!ValueRefInfo) {
716-
return AddCodableContext();
717-
}
718-
if (!ValueRefInfo->isRef()) {
719-
if (auto *NomDecl = dyn_cast<NominalTypeDecl>(ValueRefInfo->getValueD())) {
720-
return AddCodableContext(NomDecl);
721-
}
722-
}
723-
// TODO: support extensions
724-
// (would need to get synthesized nodes from the main decl,
725-
// and only if it's in the same file?)
726-
return AddCodableContext();
727-
}
728-
729-
bool RefactoringActionAddExplicitCodableImplementation::isApplicable(
730-
ResolvedCursorInfoPtr Tok, DiagnosticEngine &Diag) {
731-
return AddCodableContext::getDeclarationContextFromInfo(Tok).isValid();
732-
}
733-
734-
bool RefactoringActionAddExplicitCodableImplementation::performChange() {
735-
auto Context = AddCodableContext::getDeclarationContextFromInfo(CursorInfo);
736-
737-
SmallString<64> Buffer;
738-
llvm::raw_svector_ostream OS(Buffer);
739-
Context.printInsertionText(CursorInfo, SM, OS);
740-
741-
EditConsumer.insertAfter(SM, Context.getInsertStartLoc(), OS.str());
742-
return false;
743-
}
744-
745569
static CharSourceRange
746570
findSourceRangeToWrapInCatch(const ResolvedExprStartCursorInfo &CursorInfo,
747571
SourceFile *TheFile, SourceManager &SM) {

0 commit comments

Comments
 (0)