clang-tools  15.0.0git
SpecialMembers.cpp
Go to the documentation of this file.
1 //===--- SpecialMembers.cpp - Generate C++ special member functions -------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 #include "ParsedAST.h"
10 #include "refactor/Tweak.h"
11 #include "support/Logger.h"
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"
20 
21 namespace clang {
22 namespace clangd {
23 namespace {
24 
25 // Returns code to declare missing copy/move constructors/assignment operators.
26 // They will be deleted or defaulted to match the class's current state.
27 std::string buildSpecialMemberDeclarations(const CXXRecordDecl &Class) {
28  struct Members {
29  const CXXMethodDecl *Copy = nullptr;
30  const CXXMethodDecl *Move = nullptr;
31  } Ctor, Assign;
32 
33  for (const auto &M : Class.methods()) {
34  if (M->isCopyAssignmentOperator())
35  Assign.Copy = M;
36  else if (M->isMoveAssignmentOperator())
37  Assign.Move = M;
38  if (const auto *C = llvm::dyn_cast<CXXConstructorDecl>(M)) {
39  if (C->isCopyConstructor())
40  Ctor.Copy = C;
41  else if (C->isMoveConstructor())
42  Ctor.Move = C;
43  }
44  }
45 
46  std::string S;
47  llvm::raw_string_ostream OS(S);
48 
49  auto PrintMember = [&](const CXXMethodDecl *D, const char *MemberPattern,
50  const char *ParmPattern) {
51  if (D && !D->isImplicit())
52  return;
53  bool Delete = !D || D->isDeleted();
54  OS << llvm::formatv(
55  "{0} = {1};\n",
56  llvm::formatv(MemberPattern, Class.getName(),
57  llvm::formatv(ParmPattern, Class.getName())),
58  Delete ? "delete" : "default");
59  };
60  auto PrintMembers = [&](const Members &M, const char *MemberPattern) {
61  PrintMember(M.Copy, MemberPattern, /*ParmPattern=*/"const {0}&");
62  PrintMember(M.Move, MemberPattern, /*ParmPattern=*/"{0}&&");
63  };
64  PrintMembers(Ctor, /*MemberPattern=*/"{0}({1})");
65  PrintMembers(Assign, /*MemberPattern=*/"{0} &operator=({1})");
66 
67  return S;
68 }
69 
70 // A tweak that adds missing declarations of copy & move constructors.
71 //
72 // e.g. given `struct ^S{};`, produces:
73 // struct S {
74 // S(const S&) = default;
75 // S(S&&) = default;
76 // S &operator=(const S&) = default;
77 // S &operator=(S&&) = default;
78 // };
79 //
80 // Added members are defaulted or deleted to approximately preserve semantics.
81 // (May not be a strict no-op when they were not implicitly declared).
82 //
83 // Having these spelled out is useful:
84 // - to understand the implicit behavior
85 // - to avoid relying on the implicit behavior
86 // - as a baseline for explicit modification
87 class DeclareCopyMove : public Tweak {
88 public:
89  const char *id() const override final;
90  llvm::StringLiteral kind() const override {
92  }
93  std::string title() const override {
94  return llvm::formatv("Declare implicit {0} members",
95  NeedCopy ? NeedMove ? "copy/move" : "copy" : "move");
96  }
97 
98  bool prepare(const Selection &Inputs) override {
99  // This tweak relies on =default and =delete.
100  if (!Inputs.AST->getLangOpts().CPlusPlus11)
101  return false;
102 
103  // Trigger only on class definitions.
104  if (auto *N = Inputs.ASTSelection.commonAncestor())
105  Class = const_cast<CXXRecordDecl *>(N->ASTNode.get<CXXRecordDecl>());
106  if (!Class || !Class->isThisDeclarationADefinition())
107  return false;
108 
109  // Tweak is only available if some members are missing.
110  NeedCopy = !Class->hasUserDeclaredCopyConstructor() ||
111  !Class->hasUserDeclaredCopyAssignment();
112  NeedMove = !Class->hasUserDeclaredMoveAssignment() ||
113  !Class->hasUserDeclaredMoveConstructor();
114  return NeedCopy || NeedMove;
115  }
116 
117  Expected<Effect> apply(const Selection &Inputs) override {
118  // Implicit special members are created lazily by clang.
119  // We need them so we can tell whether they should be =default or =delete.
120  Inputs.AST->getSema().ForceDeclarationOfImplicitMembers(Class);
121  std::string Code = buildSpecialMemberDeclarations(*Class);
122 
123  // Prefer to place the new members...
124  std::vector<Anchor> Anchors = {
125  // Below the default constructor
126  {[](const Decl *D) {
127  if (const auto *CCD = llvm::dyn_cast<CXXConstructorDecl>(D))
128  return CCD->isDefaultConstructor();
129  return false;
130  },
131  Anchor::Below},
132  // Above existing constructors
133  {[](const Decl *D) { return llvm::isa<CXXConstructorDecl>(D); },
134  Anchor::Above},
135  // At the top of the public section
136  {[](const Decl *D) { return true; }, Anchor::Above},
137  };
138  auto Edit = insertDecl(Code, *Class, std::move(Anchors), AS_public);
139  if (!Edit)
140  return Edit.takeError();
141  return Effect::mainFileEdit(Inputs.AST->getSourceManager(),
142  tooling::Replacements{std::move(*Edit)});
143  }
144 
145 private:
146  bool NeedCopy = false, NeedMove = false;
147  CXXRecordDecl *Class = nullptr;
148 };
149 REGISTER_TWEAK(DeclareCopyMove)
150 
151 } // namespace
152 } // namespace clangd
153 } // namespace clang
clang::clangd::Anchor::Below
@ Below
Definition: InsertionPoint.h:25
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
clang::clangd::insertDecl
llvm::Expected< tooling::Replacement > insertDecl(llvm::StringRef Code, const DeclContext &DC, llvm::ArrayRef< Anchor > Anchors)
Definition: InsertionPoint.cpp:111
M
const google::protobuf::Message & M
Definition: Server.cpp:309
Inputs
ParseInputs Inputs
Definition: TUScheduler.cpp:544
Code
std::string Code
Definition: FindTargetTests.cpp:67
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
Tweak.h
Logger.h
InsertionPoint.h
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:160
clang::clangd::Anchor::Above
@ Above
Definition: InsertionPoint.h:25
clang::clangd::CodeAction::REFACTOR_KIND
const static llvm::StringLiteral REFACTOR_KIND
Definition: Protocol.h:1000
REGISTER_TWEAK
#define REGISTER_TWEAK(Subclass)
Definition: Tweak.h:129
ParsedAST.h