@@ -3526,6 +3526,177 @@ performChange() {
35263526 return false ;
35273527}
35283528
3529+ class AddCodableContext {
3530+
3531+ // / Declaration context
3532+ DeclContext *DC;
3533+
3534+ // / Start location of declaration context brace
3535+ SourceLoc StartLoc;
3536+
3537+ // / Array of all conformed protocols
3538+ SmallVector<swift::ProtocolDecl *, 2 > Protocols;
3539+
3540+ // / Range of internal members in declaration
3541+ DeclRange Range;
3542+
3543+ bool conformsToCodableProtocol () {
3544+ for (ProtocolDecl *Protocol : Protocols) {
3545+ if (Protocol->getKnownProtocolKind () == KnownProtocolKind::Encodable ||
3546+ Protocol->getKnownProtocolKind () == KnownProtocolKind::Decodable) {
3547+ return true ;
3548+ }
3549+ }
3550+ return false ;
3551+ }
3552+
3553+ public:
3554+ AddCodableContext (NominalTypeDecl *Decl)
3555+ : DC(Decl), StartLoc(Decl->getBraces ().Start),
3556+ Protocols(Decl->getAllProtocols ()), Range(Decl->getMembers ()){};
3557+
3558+ AddCodableContext (ExtensionDecl *Decl)
3559+ : DC(Decl), StartLoc(Decl->getBraces ().Start),
3560+ Protocols(Decl->getExtendedNominal ()->getAllProtocols()),
3561+ Range(Decl->getMembers ()){};
3562+
3563+ AddCodableContext () : DC(nullptr ), Protocols(), Range(nullptr , nullptr ){};
3564+
3565+ static AddCodableContext
3566+ getDeclarationContextFromInfo (const ResolvedCursorInfo &Info);
3567+
3568+ void printInsertionText (const ResolvedCursorInfo &CursorInfo,
3569+ SourceManager &SM, llvm::raw_ostream &OS);
3570+
3571+ bool isValid () { return StartLoc.isValid () && conformsToCodableProtocol (); }
3572+
3573+ SourceLoc getInsertStartLoc ();
3574+ };
3575+
3576+ SourceLoc AddCodableContext::getInsertStartLoc () {
3577+ SourceLoc MaxLoc = StartLoc;
3578+ for (auto Mem : Range) {
3579+ if (Mem->getEndLoc ().getOpaquePointerValue () >
3580+ MaxLoc.getOpaquePointerValue ()) {
3581+ MaxLoc = Mem->getEndLoc ();
3582+ }
3583+ }
3584+ return MaxLoc;
3585+ }
3586+
3587+ // / Walks an AST and prints the synthesized Codable implementation.
3588+ class SynthesizedCodablePrinter : public ASTWalker {
3589+ private:
3590+ ASTPrinter &Printer;
3591+
3592+ public:
3593+ SynthesizedCodablePrinter (ASTPrinter &Printer) : Printer(Printer) {}
3594+
3595+ bool walkToDeclPre (Decl *D) override {
3596+ auto *VD = dyn_cast<ValueDecl>(D);
3597+ if (!VD)
3598+ return false ;
3599+
3600+ if (!VD->isSynthesized ()) {
3601+ return true ;
3602+ }
3603+ SmallString<32 > Scratch;
3604+ auto name = VD->getName ().getString (Scratch);
3605+ // Print all synthesized enums,
3606+ // since Codable can synthesize multiple enums (for associated values).
3607+ auto shouldPrint =
3608+ isa<EnumDecl>(VD) || name == " init(from:)" || name == " encode(to:)" ;
3609+ if (!shouldPrint) {
3610+ // Some other synthesized decl that we don't want to print.
3611+ return false ;
3612+ }
3613+
3614+ Printer.printNewline ();
3615+
3616+ if (auto enumDecl = dyn_cast<EnumDecl>(D)) {
3617+ // Manually print enum here, since we don't want to print synthesized
3618+ // functions.
3619+ Printer << " enum " << enumDecl->getNameStr ();
3620+ PrintOptions Options;
3621+ Options.PrintSpaceBeforeInheritance = false ;
3622+ enumDecl->printInherited (Printer, Options);
3623+ Printer << " {" ;
3624+ for (Decl *EC : enumDecl->getAllElements ()) {
3625+ Printer.printNewline ();
3626+ Printer << " " ;
3627+ EC->print (Printer, Options);
3628+ }
3629+ Printer.printNewline ();
3630+ Printer << " }" ;
3631+ return false ;
3632+ }
3633+
3634+ PrintOptions Options;
3635+ Options.SynthesizeSugarOnTypes = true ;
3636+ Options.FunctionDefinitions = true ;
3637+ Options.VarInitializers = true ;
3638+ Options.PrintExprs = true ;
3639+ Options.TypeDefinitions = true ;
3640+ Options.ExcludeAttrList .push_back (DAK_HasInitialValue);
3641+
3642+ Printer.printNewline ();
3643+ D->print (Printer, Options);
3644+
3645+ return false ;
3646+ }
3647+ };
3648+
3649+ void AddCodableContext::printInsertionText (const ResolvedCursorInfo &CursorInfo,
3650+ SourceManager &SM,
3651+ llvm::raw_ostream &OS) {
3652+ StringRef ExtraIndent;
3653+ StringRef CurrentIndent =
3654+ Lexer::getIndentationForLine (SM, getInsertStartLoc (), &ExtraIndent);
3655+ std::string Indent;
3656+ if (getInsertStartLoc () == StartLoc) {
3657+ Indent = (CurrentIndent + ExtraIndent).str ();
3658+ } else {
3659+ Indent = CurrentIndent.str ();
3660+ }
3661+
3662+ ExtraIndentStreamPrinter Printer (OS, Indent);
3663+ Printer.printNewline ();
3664+ SynthesizedCodablePrinter Walker (Printer);
3665+ DC->getAsDecl ()->walk (Walker);
3666+ }
3667+
3668+ AddCodableContext AddCodableContext::getDeclarationContextFromInfo (
3669+ const ResolvedCursorInfo &Info) {
3670+ if (Info.isInvalid ()) {
3671+ return AddCodableContext ();
3672+ }
3673+ if (!Info.IsRef ) {
3674+ if (auto *NomDecl = dyn_cast<NominalTypeDecl>(Info.ValueD )) {
3675+ return AddCodableContext (NomDecl);
3676+ }
3677+ }
3678+ // TODO: support extensions
3679+ // (would need to get synthesized nodes from the main decl,
3680+ // and only if it's in the same file?)
3681+ return AddCodableContext ();
3682+ }
3683+
3684+ bool RefactoringActionAddExplicitCodableImplementation::isApplicable (
3685+ const ResolvedCursorInfo &Tok, DiagnosticEngine &Diag) {
3686+ return AddCodableContext::getDeclarationContextFromInfo (Tok).isValid ();
3687+ }
3688+
3689+ bool RefactoringActionAddExplicitCodableImplementation::performChange () {
3690+ auto Context = AddCodableContext::getDeclarationContextFromInfo (CursorInfo);
3691+
3692+ SmallString<64 > Buffer;
3693+ llvm::raw_svector_ostream OS (Buffer);
3694+ Context.printInsertionText (CursorInfo, SM, OS);
3695+
3696+ EditConsumer.insertAfter (SM, Context.getInsertStartLoc (), OS.str ());
3697+ return false ;
3698+ }
3699+
35293700static CharSourceRange
35303701findSourceRangeToWrapInCatch (const ResolvedCursorInfo &CursorInfo,
35313702 SourceFile *TheFile,
0 commit comments