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