diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp | 69 |
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 |