clang-tools  3.8.0
UndelegatedConstructor.cpp
Go to the documentation of this file.
1 //===--- UndelegatedConstructor.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 "UndelegatedConstructor.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/Lex/Lexer.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 
18 namespace {
19 AST_MATCHER_P(Stmt, ignoringTemporaryExpr,
20  ast_matchers::internal::Matcher<Stmt>, InnerMatcher) {
21  const Stmt *E = &Node;
22  for (;;) {
23  // Temporaries with non-trivial dtors.
24  if (const auto *EWC = dyn_cast<ExprWithCleanups>(E))
25  E = EWC->getSubExpr();
26  // Temporaries with zero or more than two ctor arguments.
27  else if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
28  E = BTE->getSubExpr();
29  // Temporaries with exactly one ctor argument.
30  else if (const auto *FCE = dyn_cast<CXXFunctionalCastExpr>(E))
31  E = FCE->getSubExpr();
32  else
33  break;
34  }
35 
36  return InnerMatcher.matches(*E, Finder, Builder);
37 }
38 
39 // Finds a node if it's a base of an already bound node.
40 AST_MATCHER_P(CXXRecordDecl, baseOfBoundNode, std::string, ID) {
41  return Builder->removeBindings(
42  [&](const ast_matchers::internal::BoundNodesMap &Nodes) {
43  const auto *Derived = Nodes.getNodeAs<CXXRecordDecl>(ID);
44  return Derived != &Node && !Derived->isDerivedFrom(&Node);
45  });
46 }
47 } // namespace
48 
49 namespace tidy {
50 namespace misc {
51 
52 void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) {
53  // We look for calls to constructors of the same type in constructors. To do
54  // this we have to look through a variety of nodes that occur in the path,
55  // depending on the type's destructor and the number of arguments on the
56  // constructor call, this is handled by ignoringTemporaryExpr. Ignore template
57  // instantiations to reduce the number of duplicated warnings.
58  //
59  // Only register the matchers for C++11; the functionality currently does not
60  // provide any benefit to other languages, despite being benign.
61  if (!getLangOpts().CPlusPlus11)
62  return;
63 
64  Finder->addMatcher(
65  compoundStmt(
66  hasParent(
67  cxxConstructorDecl(ofClass(cxxRecordDecl().bind("parent")))),
68  forEach(ignoringTemporaryExpr(
69  cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass(
70  cxxRecordDecl(baseOfBoundNode("parent"))))))
71  .bind("construct"))),
72  unless(isInTemplateInstantiation())),
73  this);
74 }
75 
76 void UndelegatedConstructorCheck::check(const MatchFinder::MatchResult &Result) {
77  const auto *E = Result.Nodes.getStmtAs<CXXConstructExpr>("construct");
78  diag(E->getLocStart(), "did you intend to call a delegated constructor? "
79  "A temporary object is created here instead");
80 }
81 
82 } // namespace misc
83 } // namespace tidy
84 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
AST_MATCHER_P(CXXForRangeStmt, hasRangeBeginEndStmt, ast_matchers::internal::Matcher< DeclStmt >, InnerMatcher)
const NamedDecl * Result
Definition: USRFinder.cpp:121