summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
diff options
context:
space:
mode:
authorJonathan Coe <jbcoe@me.com>2016-07-30 08:58:54 +0000
committerJonathan Coe <jbcoe@me.com>2016-07-30 08:58:54 +0000
commit5d304b2456afba562855a692a5ea4d10cc5da9e7 (patch)
tree6714b10b6672049bfa6ec9d3a0676a886b092ec5 /clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
parentfcfec5fdef79cb4d96033aaabdb8286912d131ea (diff)
downloadbcm5719-llvm-5d304b2456afba562855a692a5ea4d10cc5da9e7.tar.gz
bcm5719-llvm-5d304b2456afba562855a692a5ea4d10cc5da9e7.zip
[clang-tidy] add check cppcoreguidelines-special-member-functions
Summary: Check for classes that violate the rule of five and zero as specified in CppCoreGuidelines: "If a class defines or deletes a default operation then it should define or delete them all." https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all. Reviewers: alexfh, sbenza, aaron.ballman Subscribers: Prazek, Eugene.Zelenko, cfe-commits, ericLemanissier, nemanjai Projects: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D22513 llvm-svn: 277262
Diffstat (limited to 'clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp133
1 files changed, 133 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
new file mode 100644
index 00000000000..9a0ffa97a86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
@@ -0,0 +1,133 @@
+//===--- SpecialMemberFunctionsCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SpecialMemberFunctionsCheck.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/StringExtras.h"
+
+#define DEBUG_TYPE "clang-tidy"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Finder->addMatcher(
+ cxxRecordDecl(
+ eachOf(
+ has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")),
+ has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))
+ .bind("copy-ctor")),
+ has(cxxMethodDecl(isCopyAssignmentOperator(),
+ unless(isImplicit()))
+ .bind("copy-assign")),
+ has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))
+ .bind("move-ctor")),
+ has(cxxMethodDecl(isMoveAssignmentOperator(),
+ unless(isImplicit()))
+ .bind("move-assign"))))
+ .bind("class-def"),
+ this);
+}
+
+llvm::StringRef SpecialMemberFunctionsCheck::toString(
+ SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K) {
+ switch (K) {
+ case SpecialMemberFunctionKind::Destructor:
+ return "a destructor";
+ case SpecialMemberFunctionKind::CopyConstructor:
+ return "a copy constructor";
+ case SpecialMemberFunctionKind::CopyAssignment:
+ return "a copy assignment operator";
+ case SpecialMemberFunctionKind::MoveConstructor:
+ return "a move constructor";
+ case SpecialMemberFunctionKind::MoveAssignment:
+ return "a move assignment operator";
+ }
+ llvm_unreachable("Unhandled SpecialMemberFunctionKind");
+}
+
+std::string SpecialMemberFunctionsCheck::join(
+ llvm::ArrayRef<SpecialMemberFunctionKind> SMFS, llvm::StringRef AndOr) {
+
+ assert(!SMFS.empty() &&
+ "List of defined or undefined members should never be empty.");
+ std::string Buffer;
+ llvm::raw_string_ostream Stream(Buffer);
+
+ Stream << toString(SMFS[0]);
+ size_t LastIndex = SMFS.size() - 1;
+ for (size_t i = 1; i < LastIndex; ++i) {
+ Stream << ", " << toString(SMFS[i]);
+ }
+ if (LastIndex != 0) {
+ Stream << AndOr << toString(SMFS[LastIndex]);
+ }
+ return Stream.str();
+}
+
+void SpecialMemberFunctionsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const CXXRecordDecl *MatchedDecl =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("class-def");
+ if (!MatchedDecl)
+ return;
+
+ ClassDefId ID(MatchedDecl->getLocation(), MatchedDecl->getName());
+
+ std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>>
+ Matchers = {{"dtor", SpecialMemberFunctionKind::Destructor},
+ {"copy-ctor", SpecialMemberFunctionKind::CopyConstructor},
+ {"copy-assign", SpecialMemberFunctionKind::CopyAssignment},
+ {"move-ctor", SpecialMemberFunctionKind::MoveConstructor},
+ {"move-assign", SpecialMemberFunctionKind::MoveAssignment}};
+
+ for (const auto &KV : Matchers)
+ if (Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first))
+ ClassWithSpecialMembers[ID].push_back(KV.second);
+}
+
+void SpecialMemberFunctionsCheck::onEndOfTranslationUnit() {
+ llvm::SmallVector<SpecialMemberFunctionKind, 5> AllSpecialMembers = {
+ SpecialMemberFunctionKind::Destructor,
+ SpecialMemberFunctionKind::CopyConstructor,
+ SpecialMemberFunctionKind::CopyAssignment};
+
+ if (getLangOpts().CPlusPlus11) {
+ AllSpecialMembers.push_back(SpecialMemberFunctionKind::MoveConstructor);
+ AllSpecialMembers.push_back(SpecialMemberFunctionKind::MoveAssignment);
+ }
+
+ for (const auto &C : ClassWithSpecialMembers) {
+ ArrayRef<SpecialMemberFunctionKind> DefinedSpecialMembers = C.second;
+
+ if (DefinedSpecialMembers.size() == AllSpecialMembers.size())
+ continue;
+
+ llvm::SmallVector<SpecialMemberFunctionKind, 5> UndefinedSpecialMembers;
+ std::set_difference(AllSpecialMembers.begin(), AllSpecialMembers.end(),
+ DefinedSpecialMembers.begin(),
+ DefinedSpecialMembers.end(),
+ std::back_inserter(UndefinedSpecialMembers));
+
+ diag(C.first.first, "class '%0' defines %1 but does not define %2")
+ << C.first.second << join(DefinedSpecialMembers, " and ")
+ << join(UndefinedSpecialMembers, " or ");
+ }
+}
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
OpenPOWER on IntegriCloud