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