blob: ff2f00b94e36c0117d29397d23ac6462b059bb56 [file] [log] [blame]
Alexander Kornienko4191b902016-04-13 11:33:40 +00001//===--- DeletedDefaultCheck.cpp - clang-tidy------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Alexander Kornienko4191b902016-04-13 11:33:40 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "DeletedDefaultCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang {
16namespace tidy {
17namespace readability {
18
19void DeletedDefaultCheck::registerMatchers(MatchFinder *Finder) {
20 // We match constructors/assignment operators that are:
21 // - explicitly marked '= default'
22 // - actually deleted
23 // - not in template instantiation.
24 // We bind the declaration to "method-decl" and also to "constructor" when
25 // it is a constructor.
26
27 Finder->addMatcher(
28 cxxMethodDecl(anyOf(cxxConstructorDecl().bind("constructor"),
29 isCopyAssignmentOperator(),
30 isMoveAssignmentOperator()),
31 isDefaulted(), unless(isImplicit()), isDeleted(),
32 unless(isInstantiated()))
33 .bind("method-decl"),
34 this);
35}
36
37void DeletedDefaultCheck::check(const MatchFinder::MatchResult &Result) {
38 const StringRef Message = "%0 is explicitly defaulted but implicitly "
39 "deleted, probably because %1; definition can "
40 "either be removed or explicitly deleted";
41 if (const auto *Constructor =
42 Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor")) {
Stephen Kelly43465bf2018-08-09 22:42:26 +000043 auto Diag = diag(Constructor->getBeginLoc(), Message);
Alexander Kornienko4191b902016-04-13 11:33:40 +000044 if (Constructor->isDefaultConstructor()) {
45 Diag << "default constructor"
46 << "a non-static data member or a base class is lacking a default "
47 "constructor";
48 } else if (Constructor->isCopyConstructor()) {
49 Diag << "copy constructor"
50 << "a non-static data member or a base class is not copyable";
51 } else if (Constructor->isMoveConstructor()) {
52 Diag << "move constructor"
53 << "a non-static data member or a base class is neither copyable "
54 "nor movable";
55 }
56 } else if (const auto *Assignment =
57 Result.Nodes.getNodeAs<CXXMethodDecl>("method-decl")) {
Stephen Kelly43465bf2018-08-09 22:42:26 +000058 diag(Assignment->getBeginLoc(), Message)
Alexander Kornienko4191b902016-04-13 11:33:40 +000059 << (Assignment->isCopyAssignmentOperator() ? "copy assignment operator"
60 : "move assignment operator")
61 << "a base class or a non-static data member is not assignable, e.g. "
62 "because the latter is marked 'const'";
63 }
64}
65
66} // namespace readability
67} // namespace tidy
68} // namespace clang