clang-tools 6.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
clang::ast_matchers
Definition: ClangTidyDiagnosticConsumer.h:27
UnusedRAIICheck.h
clang
Definition: AndroidTidyModule.cpp:28
clang::ast_matchers::AST_MATCHER
AST_MATCHER(VarDecl, isAsm)
Definition: NoAssemblerCheck.cpp:18