clang-tools 19.0.0git
UnusedRaiiCheck.cpp
Go to the documentation of this file.
1//===--- UnusedRaiiCheck.cpp - clang-tidy ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "UnusedRaiiCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/Lex/Lexer.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang::tidy::bugprone {
16
17namespace {
18AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {
19 // TODO: If the dtor is there but empty we don't want to warn either.
20 return Node.hasDefinition() && Node.hasNonTrivialDestructor();
21}
22} // namespace
23
24void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) {
25 // Look for temporaries that are constructed in-place and immediately
26 // destroyed.
27 Finder->addMatcher(
28 mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)
29 .with(hasParent(compoundStmt().bind("compound")),
30 anyOf(hasType(hasCanonicalType(recordType(hasDeclaration(
31 cxxRecordDecl(hasNonTrivialDestructor()))))),
32 hasType(hasCanonicalType(templateSpecializationType(
33 hasDeclaration(classTemplateDecl(has(
34 cxxRecordDecl(hasNonTrivialDestructor())))))))))
35 .bind("expr"),
36 this);
37}
38
39template <typename T>
40void reportDiagnostic(DiagnosticBuilder D, const T *Node, SourceRange SR,
41 bool DefaultConstruction) {
42 const char *Replacement = " give_me_a_name";
43
44 // If this is a default ctor we have to remove the parens or we'll introduce a
45 // most vexing parse.
46 if (DefaultConstruction) {
47 D << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(SR),
48 Replacement);
49 return;
50 }
51
52 // Otherwise just suggest adding a name. To find the place to insert the name
53 // find the first TypeLoc in the children of E, which always points to the
54 // written type.
55 D << FixItHint::CreateInsertion(SR.getBegin(), Replacement);
56}
57
58void UnusedRaiiCheck::check(const MatchFinder::MatchResult &Result) {
59 const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
60
61 // We ignore code expanded from macros to reduce the number of false
62 // positives.
63 if (E->getBeginLoc().isMacroID())
64 return;
65
66 // Don't emit a warning for the last statement in the surrounding compound
67 // statement.
68 const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("compound");
69 const auto *LastExpr = dyn_cast<Expr>(CS->body_back());
70
71 if (LastExpr && E == LastExpr->IgnoreUnlessSpelledInSource())
72 return;
73
74 // Emit a warning.
75 auto D = diag(E->getBeginLoc(), "object destroyed immediately after "
76 "creation; did you mean to name the object?");
77
78 if (const auto *Node = dyn_cast<CXXConstructExpr>(E))
79 reportDiagnostic(D, Node, Node->getParenOrBraceRange(),
80 Node->getNumArgs() == 0 ||
81 isa<CXXDefaultArgExpr>(Node->getArg(0)));
82 if (const auto *Node = dyn_cast<CXXUnresolvedConstructExpr>(E)) {
83 auto SR = SourceRange(Node->getLParenLoc(), Node->getRParenLoc());
84 auto DefaultConstruction = Node->getNumArgs() == 0;
85 if (!DefaultConstruction) {
86 auto *FirstArg = Node->getArg(0);
87 DefaultConstruction = isa<CXXDefaultArgExpr>(FirstArg);
88 if (auto *ILE = dyn_cast<InitListExpr>(FirstArg)) {
89 DefaultConstruction = ILE->getNumInits() == 0;
90 SR = SourceRange(ILE->getLBraceLoc(), ILE->getRBraceLoc());
91 }
92 }
93 reportDiagnostic(D, Node, SR, DefaultConstruction);
94 }
95}
96
97} // namespace clang::tidy::bugprone
const Expr * E
::clang::DynTypedNode Node
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
AST_MATCHER(clang::VarDecl, hasConstantDeclaration)
void reportDiagnostic(DiagnosticBuilder D, const T *Node, SourceRange SR, bool DefaultConstruction)