1 //===--- DeletedDefaultCheck.cpp - clang-tidy------------------------------===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DeletedDefaultCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace readability {
18 
registerMatchers(MatchFinder * Finder)19 void 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 
check(const MatchFinder::MatchResult & Result)37 void 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")) {
43     auto Diag = diag(Constructor->getBeginLoc(), Message);
44     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")) {
58     diag(Assignment->getBeginLoc(), Message)
59         << (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
69