summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp69
1 files changed, 69 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp b/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp
new file mode 100644
index 00000000000..a197e8dcdd4
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp
@@ -0,0 +1,69 @@
+//===--- DeletedDefaultCheck.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 "DeletedDefaultCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void DeletedDefaultCheck::registerMatchers(MatchFinder *Finder) {
+ // We match constructors/assignment operators that are:
+ // - explicitly marked '= default'
+ // - actually deleted
+ // - not in template instantiation.
+ // We bind the declaration to "method-decl" and also to "constructor" when
+ // it is a constructor.
+
+ Finder->addMatcher(
+ cxxMethodDecl(anyOf(cxxConstructorDecl().bind("constructor"),
+ isCopyAssignmentOperator(),
+ isMoveAssignmentOperator()),
+ isDefaulted(), unless(isImplicit()), isDeleted(),
+ unless(isInstantiated()))
+ .bind("method-decl"),
+ this);
+}
+
+void DeletedDefaultCheck::check(const MatchFinder::MatchResult &Result) {
+ const StringRef Message = "%0 is explicitly defaulted but implicitly "
+ "deleted, probably because %1; definition can "
+ "either be removed or explicitly deleted";
+ if (const auto *Constructor =
+ Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor")) {
+ auto Diag = diag(Constructor->getLocStart(), Message);
+ if (Constructor->isDefaultConstructor()) {
+ Diag << "default constructor"
+ << "a non-static data member or a base class is lacking a default "
+ "constructor";
+ } else if (Constructor->isCopyConstructor()) {
+ Diag << "copy constructor"
+ << "a non-static data member or a base class is not copyable";
+ } else if (Constructor->isMoveConstructor()) {
+ Diag << "move constructor"
+ << "a non-static data member or a base class is neither copyable "
+ "nor movable";
+ }
+ } else if (const auto *Assignment =
+ Result.Nodes.getNodeAs<CXXMethodDecl>("method-decl")) {
+ diag(Assignment->getLocStart(), Message)
+ << (Assignment->isCopyAssignmentOperator() ? "copy assignment operator"
+ : "move assignment operator")
+ << "a base class or a non-static data member is not assignable, e.g. "
+ "because the latter is marked 'const'";
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
OpenPOWER on IntegriCloud