10 #include "clang/AST/ASTContext.h"
11 #include "clang/Lex/Lexer.h"
20 AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {
22 return Node.hasDefinition() && Node.hasNonTrivialDestructor();
26 void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) {
30 auto BindTemp = cxxBindTemporaryExpr(
31 unless(has(ignoringParenImpCasts(callExpr()))),
32 unless(has(ignoringParenImpCasts(objcMessageExpr()))))
35 traverse(ast_type_traits::TK_AsIs,
37 unless(isInTemplateInstantiation()),
38 hasParent(compoundStmt().bind(
"compound")),
39 hasType(cxxRecordDecl(hasNonTrivialDestructor())),
40 anyOf(has(ignoringParenImpCasts(BindTemp)),
41 has(ignoringParenImpCasts(cxxFunctionalCastExpr(
42 has(ignoringParenImpCasts(BindTemp)))))))
47 void UnusedRaiiCheck::check(
const MatchFinder::MatchResult &Result) {
48 const auto *
E = Result.Nodes.getNodeAs<Expr>(
"expr");
52 if (
E->getBeginLoc().isMacroID())
57 const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>(
"compound");
58 if (
E == CS->body_back())
62 auto D = diag(
E->getBeginLoc(),
"object destroyed immediately after "
63 "creation; did you mean to name the object?");
64 const char *Replacement =
" give_me_a_name";
68 const auto *BTE = Result.Nodes.getNodeAs<CXXBindTemporaryExpr>(
"temp");
69 if (
const auto *TOE = dyn_cast<CXXTemporaryObjectExpr>(BTE->getSubExpr()))
70 if (TOE->getNumArgs() == 0) {
71 D << FixItHint::CreateReplacement(
72 CharSourceRange::getTokenRange(TOE->getParenOrBraceRange()),
81 match(expr(hasDescendant(typeLoc().bind(
"t"))), *
E, *Result.Context);
82 const auto *TL = selectFirst<TypeLoc>(
"t", Matches);
84 D << FixItHint::CreateInsertion(
85 Lexer::getLocForEndOfToken(TL->getEndLoc(), 0, *Result.SourceManager,