comparison clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp @ 173:0572611fdcc8 llvm10 llvm12

reorgnization done
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 11:55:54 +0900
parents 1d019706d866
children 2e18cbf3894f
comparison
equal deleted inserted replaced
172:9fbae9c8bf63 173:0572611fdcc8
21 namespace tidy { 21 namespace tidy {
22 namespace cppcoreguidelines { 22 namespace cppcoreguidelines {
23 23
24 SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck( 24 SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck(
25 StringRef Name, ClangTidyContext *Context) 25 StringRef Name, ClangTidyContext *Context)
26 : ClangTidyCheck(Name, Context), 26 : ClangTidyCheck(Name, Context), AllowMissingMoveFunctions(Options.get(
27 AllowMissingMoveFunctions(Options.get("AllowMissingMoveFunctions", 0)), 27 "AllowMissingMoveFunctions", false)),
28 AllowSoleDefaultDtor(Options.get("AllowSoleDefaultDtor", 0)) {} 28 AllowSoleDefaultDtor(Options.get("AllowSoleDefaultDtor", false)),
29 AllowMissingMoveFunctionsWhenCopyIsDeleted(
30 Options.get("AllowMissingMoveFunctionsWhenCopyIsDeleted", false)) {}
29 31
30 void SpecialMemberFunctionsCheck::storeOptions( 32 void SpecialMemberFunctionsCheck::storeOptions(
31 ClangTidyOptions::OptionMap &Opts) { 33 ClangTidyOptions::OptionMap &Opts) {
32 Options.store(Opts, "AllowMissingMoveFunctions", AllowMissingMoveFunctions); 34 Options.store(Opts, "AllowMissingMoveFunctions", AllowMissingMoveFunctions);
33 Options.store(Opts, "AllowSoleDefaultDtor", AllowSoleDefaultDtor); 35 Options.store(Opts, "AllowSoleDefaultDtor", AllowSoleDefaultDtor);
36 Options.store(Opts, "AllowMissingMoveFunctionsWhenCopyIsDeleted",
37 AllowMissingMoveFunctionsWhenCopyIsDeleted);
34 } 38 }
35 39
36 void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) { 40 void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) {
37 if (!getLangOpts().CPlusPlus)
38 return;
39 Finder->addMatcher( 41 Finder->addMatcher(
40 cxxRecordDecl( 42 cxxRecordDecl(
41 eachOf( 43 eachOf(
42 has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")), 44 has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")),
43 has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit())) 45 has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))
103 if (!MatchedDecl) 105 if (!MatchedDecl)
104 return; 106 return;
105 107
106 ClassDefId ID(MatchedDecl->getLocation(), std::string(MatchedDecl->getName())); 108 ClassDefId ID(MatchedDecl->getLocation(), std::string(MatchedDecl->getName()));
107 109
108 auto StoreMember = [this, &ID](SpecialMemberFunctionKind Kind) { 110 auto StoreMember = [this, &ID](SpecialMemberFunctionData data) {
109 llvm::SmallVectorImpl<SpecialMemberFunctionKind> &Members = 111 llvm::SmallVectorImpl<SpecialMemberFunctionData> &Members =
110 ClassWithSpecialMembers[ID]; 112 ClassWithSpecialMembers[ID];
111 if (!llvm::is_contained(Members, Kind)) 113 if (!llvm::is_contained(Members, data))
112 Members.push_back(Kind); 114 Members.push_back(std::move(data));
113 }; 115 };
114 116
115 if (const auto *Dtor = Result.Nodes.getNodeAs<CXXMethodDecl>("dtor")) { 117 if (const auto *Dtor = Result.Nodes.getNodeAs<CXXMethodDecl>("dtor")) {
116 StoreMember(Dtor->isDefaulted() 118 StoreMember({Dtor->isDefaulted()
117 ? SpecialMemberFunctionKind::DefaultDestructor 119 ? SpecialMemberFunctionKind::DefaultDestructor
118 : SpecialMemberFunctionKind::NonDefaultDestructor); 120 : SpecialMemberFunctionKind::NonDefaultDestructor,
121 Dtor->isDeleted()});
119 } 122 }
120 123
121 std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>> 124 std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>>
122 Matchers = {{"copy-ctor", SpecialMemberFunctionKind::CopyConstructor}, 125 Matchers = {{"copy-ctor", SpecialMemberFunctionKind::CopyConstructor},
123 {"copy-assign", SpecialMemberFunctionKind::CopyAssignment}, 126 {"copy-assign", SpecialMemberFunctionKind::CopyAssignment},
124 {"move-ctor", SpecialMemberFunctionKind::MoveConstructor}, 127 {"move-ctor", SpecialMemberFunctionKind::MoveConstructor},
125 {"move-assign", SpecialMemberFunctionKind::MoveAssignment}}; 128 {"move-assign", SpecialMemberFunctionKind::MoveAssignment}};
126 129
127 for (const auto &KV : Matchers) 130 for (const auto &KV : Matchers)
128 if (Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) { 131 if (const auto *MethodDecl =
129 StoreMember(KV.second); 132 Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) {
133 StoreMember({KV.second, MethodDecl->isDeleted()});
130 } 134 }
131 } 135 }
132 136
133 void SpecialMemberFunctionsCheck::onEndOfTranslationUnit() { 137 void SpecialMemberFunctionsCheck::onEndOfTranslationUnit() {
134 for (const auto &C : ClassWithSpecialMembers) { 138 for (const auto &C : ClassWithSpecialMembers) {
136 } 140 }
137 } 141 }
138 142
139 void SpecialMemberFunctionsCheck::checkForMissingMembers( 143 void SpecialMemberFunctionsCheck::checkForMissingMembers(
140 const ClassDefId &ID, 144 const ClassDefId &ID,
141 llvm::ArrayRef<SpecialMemberFunctionKind> DefinedMembers) { 145 llvm::ArrayRef<SpecialMemberFunctionData> DefinedMembers) {
142 llvm::SmallVector<SpecialMemberFunctionKind, 5> MissingMembers; 146 llvm::SmallVector<SpecialMemberFunctionKind, 5> MissingMembers;
143 147
144 auto HasMember = [&](SpecialMemberFunctionKind Kind) { 148 auto HasMember = [&](SpecialMemberFunctionKind Kind) {
145 return llvm::is_contained(DefinedMembers, Kind); 149 return llvm::any_of(DefinedMembers, [Kind](const auto &data) {
150 return data.FunctionKind == Kind;
151 });
152 };
153
154 auto IsDeleted = [&](SpecialMemberFunctionKind Kind) {
155 return llvm::any_of(DefinedMembers, [Kind](const auto &data) {
156 return data.FunctionKind == Kind && data.IsDeleted;
157 });
146 }; 158 };
147 159
148 auto RequireMember = [&](SpecialMemberFunctionKind Kind) { 160 auto RequireMember = [&](SpecialMemberFunctionKind Kind) {
149 if (!HasMember(Kind)) 161 if (!HasMember(Kind))
150 MissingMembers.push_back(Kind); 162 MissingMembers.push_back(Kind);
171 183
172 RequireMember(SpecialMemberFunctionKind::CopyConstructor); 184 RequireMember(SpecialMemberFunctionKind::CopyConstructor);
173 RequireMember(SpecialMemberFunctionKind::CopyAssignment); 185 RequireMember(SpecialMemberFunctionKind::CopyAssignment);
174 } 186 }
175 187
176 if (RequireFive) { 188 if (RequireFive &&
189 !(AllowMissingMoveFunctionsWhenCopyIsDeleted &&
190 (IsDeleted(SpecialMemberFunctionKind::CopyConstructor) &&
191 IsDeleted(SpecialMemberFunctionKind::CopyAssignment)))) {
177 assert(RequireThree); 192 assert(RequireThree);
178 RequireMember(SpecialMemberFunctionKind::MoveConstructor); 193 RequireMember(SpecialMemberFunctionKind::MoveConstructor);
179 RequireMember(SpecialMemberFunctionKind::MoveAssignment); 194 RequireMember(SpecialMemberFunctionKind::MoveAssignment);
180 } 195 }
181 196
182 if (!MissingMembers.empty()) 197 if (!MissingMembers.empty()) {
198 llvm::SmallVector<SpecialMemberFunctionKind, 5> DefinedMemberKinds;
199 llvm::transform(DefinedMembers, std::back_inserter(DefinedMemberKinds),
200 [](const auto &data) { return data.FunctionKind; });
183 diag(ID.first, "class '%0' defines %1 but does not define %2") 201 diag(ID.first, "class '%0' defines %1 but does not define %2")
184 << ID.second << cppcoreguidelines::join(DefinedMembers, " and ") 202 << ID.second << cppcoreguidelines::join(DefinedMemberKinds, " and ")
185 << cppcoreguidelines::join(MissingMembers, " or "); 203 << cppcoreguidelines::join(MissingMembers, " or ");
204 }
186 } 205 }
187 206
188 } // namespace cppcoreguidelines 207 } // namespace cppcoreguidelines
189 } // namespace tidy 208 } // namespace tidy
190 } // namespace clang 209 } // namespace clang