12 #include "clang/AST/DeclCXX.h"
13 #include "clang/Basic/SourceLocation.h"
14 #include "clang/Basic/SourceManager.h"
15 #include "clang/Sema/Sema.h"
16 #include "clang/Tooling/Core/Replacement.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Casting.h"
19 #include "llvm/Support/Error.h"
27 std::string buildSpecialMemberDeclarations(
const CXXRecordDecl &Class) {
29 const CXXMethodDecl *Copy =
nullptr;
30 const CXXMethodDecl *Move =
nullptr;
33 for (
const auto &
M : Class.methods()) {
34 if (
M->isCopyAssignmentOperator())
36 else if (
M->isMoveAssignmentOperator())
38 if (
const auto *
C = llvm::dyn_cast<CXXConstructorDecl>(
M)) {
39 if (
C->isCopyConstructor())
41 else if (
C->isMoveConstructor())
47 llvm::raw_string_ostream
OS(S);
49 auto PrintMember = [&](
const CXXMethodDecl *
D,
const char *MemberPattern,
50 const char *ParmPattern) {
51 if (
D && !
D->isImplicit())
53 bool Delete = !
D ||
D->isDeleted();
56 llvm::formatv(MemberPattern, Class.getName(),
57 llvm::formatv(ParmPattern, Class.getName())),
58 Delete ?
"delete" :
"default");
60 auto PrintMembers = [&](
const Members &
M,
const char *MemberPattern) {
61 PrintMember(
M.Copy, MemberPattern,
"const {0}&");
62 PrintMember(
M.Move, MemberPattern,
"{0}&&");
64 PrintMembers(Ctor,
"{0}({1})");
65 PrintMembers(Assign,
"{0} &operator=({1})");
87 class DeclareCopyMove :
public Tweak {
89 const char *id() const override final;
90 llvm::StringLiteral kind()
const override {
93 std::string title()
const override {
94 return llvm::formatv(
"Declare implicit {0} members",
95 NeedCopy ? NeedMove ?
"copy/move" :
"copy" :
"move");
98 bool prepare(
const Selection &
Inputs)
override {
100 if (!
Inputs.AST->getLangOpts().CPlusPlus11)
104 if (
auto *N =
Inputs.ASTSelection.commonAncestor())
105 Class =
const_cast<CXXRecordDecl *
>(N->ASTNode.get<CXXRecordDecl>());
106 if (!Class || !Class->isThisDeclarationADefinition())
110 NeedCopy = !Class->hasUserDeclaredCopyConstructor() ||
111 !Class->hasUserDeclaredCopyAssignment();
112 NeedMove = !Class->hasUserDeclaredMoveAssignment() ||
113 !Class->hasUserDeclaredMoveConstructor();
114 return NeedCopy || NeedMove;
117 Expected<Effect> apply(
const Selection &
Inputs)
override {
120 Inputs.AST->getSema().ForceDeclarationOfImplicitMembers(Class);
121 std::string
Code = buildSpecialMemberDeclarations(*Class);
124 std::vector<Anchor> Anchors = {
127 if (
const auto *CCD = llvm::dyn_cast<CXXConstructorDecl>(
D))
128 return CCD->isDefaultConstructor();
133 {[](
const Decl *
D) {
return llvm::isa<CXXConstructorDecl>(
D); },
138 auto Edit =
insertDecl(
Code, *Class, std::move(Anchors), AS_public);
140 return Edit.takeError();
141 return Effect::mainFileEdit(
Inputs.AST->getSourceManager(),
142 tooling::Replacements{std::move(*Edit)});
146 bool NeedCopy =
false, NeedMove =
false;
147 CXXRecordDecl *Class =
nullptr;