1 //===--- SpecialMembers.cpp - Generate C++ special member functions -------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "refactor/InsertionPoint.h"
10 #include "refactor/Tweak.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/Sema/Sema.h"
13 #include "clang/Tooling/Core/Replacement.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/Casting.h"
16 #include "llvm/Support/Error.h"
22 // Returns code to declare missing copy/move constructors/assignment operators.
23 // They will be deleted or defaulted to match the class's current state.
24 std::string
buildSpecialMemberDeclarations(const CXXRecordDecl
&Class
) {
26 const CXXMethodDecl
*Copy
= nullptr;
27 const CXXMethodDecl
*Move
= nullptr;
30 for (const auto &M
: Class
.methods()) {
31 if (M
->isCopyAssignmentOperator())
33 else if (M
->isMoveAssignmentOperator())
35 if (const auto *C
= llvm::dyn_cast
<CXXConstructorDecl
>(M
)) {
36 if (C
->isCopyConstructor())
38 else if (C
->isMoveConstructor())
44 llvm::raw_string_ostream
OS(S
);
46 auto PrintMember
= [&](const CXXMethodDecl
*D
, const char *MemberPattern
,
47 const char *ParmPattern
) {
48 if (D
&& !D
->isImplicit())
50 bool Delete
= !D
|| D
->isDeleted();
53 llvm::formatv(MemberPattern
, Class
.getName(),
54 llvm::formatv(ParmPattern
, Class
.getName())),
55 Delete
? "delete" : "default");
57 auto PrintMembers
= [&](const Members
&M
, const char *MemberPattern
) {
58 PrintMember(M
.Copy
, MemberPattern
, /*ParmPattern=*/"const {0}&");
59 PrintMember(M
.Move
, MemberPattern
, /*ParmPattern=*/"{0}&&");
61 PrintMembers(Ctor
, /*MemberPattern=*/"{0}({1})");
62 PrintMembers(Assign
, /*MemberPattern=*/"{0} &operator=({1})");
67 // A tweak that adds missing declarations of copy & move constructors.
69 // e.g. given `struct ^S{};`, produces:
71 // S(const S&) = default;
73 // S &operator=(const S&) = default;
74 // S &operator=(S&&) = default;
77 // Added members are defaulted or deleted to approximately preserve semantics.
78 // (May not be a strict no-op when they were not implicitly declared).
80 // Having these spelled out is useful:
81 // - to understand the implicit behavior
82 // - to avoid relying on the implicit behavior
83 // - as a baseline for explicit modification
84 class SpecialMembers
: public Tweak
{
86 const char *id() const final
;
87 llvm::StringLiteral
kind() const override
{
88 return CodeAction::REFACTOR_KIND
;
90 std::string
title() const override
{
91 return llvm::formatv("Declare implicit {0} members",
92 NeedCopy
? NeedMove
? "copy/move" : "copy" : "move");
95 bool prepare(const Selection
&Inputs
) override
{
96 // This tweak relies on =default and =delete.
97 if (!Inputs
.AST
->getLangOpts().CPlusPlus11
)
100 // Trigger only on class definitions.
101 if (auto *N
= Inputs
.ASTSelection
.commonAncestor())
102 Class
= const_cast<CXXRecordDecl
*>(N
->ASTNode
.get
<CXXRecordDecl
>());
103 if (!Class
|| !Class
->isThisDeclarationADefinition() || Class
->isUnion())
106 // Tweak is only available if some members are missing.
107 NeedCopy
= !Class
->hasUserDeclaredCopyConstructor() ||
108 !Class
->hasUserDeclaredCopyAssignment();
109 NeedMove
= !Class
->hasUserDeclaredMoveAssignment() ||
110 !Class
->hasUserDeclaredMoveConstructor();
111 return NeedCopy
|| NeedMove
;
114 Expected
<Effect
> apply(const Selection
&Inputs
) override
{
115 // Implicit special members are created lazily by clang.
116 // We need them so we can tell whether they should be =default or =delete.
117 Inputs
.AST
->getSema().ForceDeclarationOfImplicitMembers(Class
);
118 std::string Code
= buildSpecialMemberDeclarations(*Class
);
120 // Prefer to place the new members...
121 std::vector
<Anchor
> Anchors
= {
122 // Below the default constructor
124 if (const auto *CCD
= llvm::dyn_cast
<CXXConstructorDecl
>(D
))
125 return CCD
->isDefaultConstructor();
129 // Above existing constructors
130 {[](const Decl
*D
) { return llvm::isa
<CXXConstructorDecl
>(D
); },
132 // At the top of the public section
133 {[](const Decl
*D
) { return true; }, Anchor::Above
},
135 auto Edit
= insertDecl(Code
, *Class
, std::move(Anchors
), AS_public
);
137 return Edit
.takeError();
138 return Effect::mainFileEdit(Inputs
.AST
->getSourceManager(),
139 tooling::Replacements
{std::move(*Edit
)});
143 bool NeedCopy
= false, NeedMove
= false;
144 CXXRecordDecl
*Class
= nullptr;
146 REGISTER_TWEAK(SpecialMembers
)
149 } // namespace clangd