clang-tools  5.0.0
UnusedRAIICheck.cpp
Go to the documentation of this file.
1 //===--- UnusedRAIICheck.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 "UnusedRAIICheck.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 namespace tidy {
18 namespace misc {
19 
20 namespace {
21 AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {
22  // TODO: If the dtor is there but empty we don't want to warn either.
23  return Node.hasDefinition() && Node.hasNonTrivialDestructor();
24 }
25 } // namespace
26 
27 void UnusedRAIICheck::registerMatchers(MatchFinder *Finder) {
28  // Only register the matchers for C++; the functionality currently does not
29  // provide any benefit to other languages, despite being benign.
30  if (!getLangOpts().CPlusPlus)
31  return;
32 
33  // Look for temporaries that are constructed in-place and immediately
34  // destroyed. Look for temporaries created by a functional cast but not for
35  // those returned from a call.
36  auto BindTemp =
37  cxxBindTemporaryExpr(unless(has(ignoringParenImpCasts(callExpr()))))
38  .bind("temp");
39  Finder->addMatcher(
40  exprWithCleanups(unless(isInTemplateInstantiation()),
41  hasParent(compoundStmt().bind("compound")),
42  hasType(cxxRecordDecl(hasNonTrivialDestructor())),
43  anyOf(has(ignoringParenImpCasts(BindTemp)),
44  has(ignoringParenImpCasts(cxxFunctionalCastExpr(
45  has(ignoringParenImpCasts(BindTemp)))))))
46  .bind("expr"),
47  this);
48 }
49 
50 void UnusedRAIICheck::check(const MatchFinder::MatchResult &Result) {
51  const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
52 
53  // We ignore code expanded from macros to reduce the number of false
54  // positives.
55  if (E->getLocStart().isMacroID())
56  return;
57 
58  // Don't emit a warning for the last statement in the surrounding compund
59  // statement.
60  const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("compound");
61  if (E == CS->body_back())
62  return;
63 
64  // Emit a warning.
65  auto D = diag(E->getLocStart(), "object destroyed immediately after "
66  "creation; did you mean to name the object?");
67  const char *Replacement = " give_me_a_name";
68 
69  // If this is a default ctor we have to remove the parens or we'll introduce a
70  // most vexing parse.
71  const auto *BTE = Result.Nodes.getNodeAs<CXXBindTemporaryExpr>("temp");
72  if (const auto *TOE = dyn_cast<CXXTemporaryObjectExpr>(BTE->getSubExpr()))
73  if (TOE->getNumArgs() == 0) {
74  D << FixItHint::CreateReplacement(
75  CharSourceRange::getTokenRange(TOE->getParenOrBraceRange()),
76  Replacement);
77  return;
78  }
79 
80  // Otherwise just suggest adding a name. To find the place to insert the name
81  // find the first TypeLoc in the children of E, which always points to the
82  // written type.
83  auto Matches =
84  match(expr(hasDescendant(typeLoc().bind("t"))), *E, *Result.Context);
85  const auto *TL = selectFirst<TypeLoc>("t", Matches);
86  D << FixItHint::CreateInsertion(
87  Lexer::getLocForEndOfToken(TL->getLocEnd(), 0, *Result.SourceManager,
88  getLangOpts()),
89  Replacement);
90 }
91 
92 } // namespace misc
93 } // namespace tidy
94 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:275
AST_MATCHER(VarDecl, isAsm)