Skip to content

Commit 7b6fc9a

Browse files
committed
[clang-tidy] Simplify unused RAII check
Fix handling of default construction where the constructor has a default arg. Differential Revision: https://reviews.llvm.org/D97142
1 parent 3d8f842 commit 7b6fc9a

File tree

3 files changed

+102
-38
lines changed

3 files changed

+102
-38
lines changed

clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,37 @@ AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {
2525

2626
void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) {
2727
// Look for temporaries that are constructed in-place and immediately
28-
// destroyed. Look for temporaries created by a functional cast but not for
29-
// those returned from a call.
30-
auto BindTemp = cxxBindTemporaryExpr(
31-
unless(has(ignoringParenImpCasts(callExpr()))),
32-
unless(has(ignoringParenImpCasts(objcMessageExpr()))))
33-
.bind("temp");
28+
// destroyed.
3429
Finder->addMatcher(
35-
traverse(TK_AsIs,
36-
exprWithCleanups(
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)))))))
43-
.bind("expr")),
30+
mapAnyOf(cxxConstructExpr, cxxUnresolvedConstructExpr)
31+
.with(hasParent(compoundStmt().bind("compound")),
32+
anyOf(hasType(cxxRecordDecl(hasNonTrivialDestructor())),
33+
hasType(templateSpecializationType(
34+
hasDeclaration(classTemplateDecl(has(
35+
cxxRecordDecl(hasNonTrivialDestructor()))))))))
36+
.bind("expr"),
4437
this);
4538
}
4639

40+
template <typename T>
41+
void reportDiagnostic(DiagnosticBuilder D, const T *Node, SourceRange SR,
42+
bool DefaultConstruction) {
43+
const char *Replacement = " give_me_a_name";
44+
45+
// If this is a default ctor we have to remove the parens or we'll introduce a
46+
// most vexing parse.
47+
if (DefaultConstruction) {
48+
D << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(SR),
49+
Replacement);
50+
return;
51+
}
52+
53+
// Otherwise just suggest adding a name. To find the place to insert the name
54+
// find the first TypeLoc in the children of E, which always points to the
55+
// written type.
56+
D << FixItHint::CreateInsertion(SR.getBegin(), Replacement);
57+
}
58+
4759
void UnusedRaiiCheck::check(const MatchFinder::MatchResult &Result) {
4860
const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
4961

@@ -55,35 +67,32 @@ void UnusedRaiiCheck::check(const MatchFinder::MatchResult &Result) {
5567
// Don't emit a warning for the last statement in the surrounding compound
5668
// statement.
5769
const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("compound");
58-
if (E == CS->body_back())
70+
const auto *LastExpr = dyn_cast<Expr>(CS->body_back());
71+
72+
if (LastExpr && E == LastExpr->IgnoreUnlessSpelledInSource())
5973
return;
6074

6175
// Emit a warning.
6276
auto D = diag(E->getBeginLoc(), "object destroyed immediately after "
6377
"creation; did you mean to name the object?");
64-
const char *Replacement = " give_me_a_name";
6578

66-
// If this is a default ctor we have to remove the parens or we'll introduce a
67-
// most vexing parse.
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()),
73-
Replacement);
74-
return;
79+
if (const auto *Node = dyn_cast<CXXConstructExpr>(E))
80+
reportDiagnostic(D, Node, Node->getParenOrBraceRange(),
81+
Node->getNumArgs() == 0 ||
82+
isa<CXXDefaultArgExpr>(Node->getArg(0)));
83+
if (const auto *Node = dyn_cast<CXXUnresolvedConstructExpr>(E)) {
84+
auto SR = SourceRange(Node->getLParenLoc(), Node->getRParenLoc());
85+
auto DefaultConstruction = Node->getNumArgs() == 0;
86+
if (!DefaultConstruction) {
87+
auto FirstArg = Node->getArg(0);
88+
DefaultConstruction = isa<CXXDefaultArgExpr>(FirstArg);
89+
if (auto ILE = dyn_cast<InitListExpr>(FirstArg)) {
90+
DefaultConstruction = ILE->getNumInits() == 0;
91+
SR = SourceRange(ILE->getLBraceLoc(), ILE->getRBraceLoc());
92+
}
7593
}
76-
77-
// Otherwise just suggest adding a name. To find the place to insert the name
78-
// find the first TypeLoc in the children of E, which always points to the
79-
// written type.
80-
auto Matches =
81-
match(expr(hasDescendant(typeLoc().bind("t"))), *E, *Result.Context);
82-
if (const auto *TL = selectFirst<TypeLoc>("t", Matches))
83-
D << FixItHint::CreateInsertion(
84-
Lexer::getLocForEndOfToken(TL->getEndLoc(), 0, *Result.SourceManager,
85-
getLangOpts()),
86-
Replacement);
94+
reportDiagnostic(D, Node, SR, DefaultConstruction);
95+
}
8796
}
8897

8998
} // namespace bugprone

clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class UnusedRaiiCheck : public ClangTidyCheck {
2828
}
2929
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
3030
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
31+
llvm::Optional<TraversalKind> getCheckTraversalKind() const override {
32+
return TK_IgnoreUnlessSpelledInSource;
33+
}
3134
};
3235

3336
} // namespace bugprone

clang-tools-extra/test/clang-tidy/checkers/bugprone-unused-raii.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %check_clang_tidy %s bugprone-unused-raii %t
1+
// RUN: %check_clang_tidy %s bugprone-unused-raii %t -- -- -fno-delayed-template-parsing
22

33
struct Foo {
44
Foo();
@@ -46,6 +46,42 @@ void neverInstantiated() {
4646
T();
4747
}
4848

49+
struct CtorDefaultArg {
50+
CtorDefaultArg(int i = 0);
51+
~CtorDefaultArg();
52+
};
53+
54+
template <typename T>
55+
struct TCtorDefaultArg {
56+
TCtorDefaultArg(T i = 0);
57+
~TCtorDefaultArg();
58+
};
59+
60+
struct CtorTwoDefaultArg {
61+
CtorTwoDefaultArg(int i = 0, bool b = false);
62+
~CtorTwoDefaultArg();
63+
};
64+
65+
template <typename T>
66+
void templatetest() {
67+
TCtorDefaultArg<T>();
68+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
69+
// CHECK-FIXES: TCtorDefaultArg<T> give_me_a_name;
70+
TCtorDefaultArg<T>{};
71+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
72+
// CHECK-FIXES: TCtorDefaultArg<T> give_me_a_name;
73+
74+
TCtorDefaultArg<T>(T{});
75+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
76+
// CHECK-FIXES: TCtorDefaultArg<T> give_me_a_name(T{});
77+
TCtorDefaultArg<T>{T{}};
78+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
79+
// CHECK-FIXES: TCtorDefaultArg<T> give_me_a_name{T{}};
80+
81+
int i = 0;
82+
(void)i;
83+
}
84+
4985
void test() {
5086
Foo(42);
5187
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
@@ -71,6 +107,22 @@ void test() {
71107
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
72108
// CHECK-FIXES: FooBar give_me_a_name;
73109

110+
CtorDefaultArg();
111+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
112+
// CHECK-FIXES: CtorDefaultArg give_me_a_name;
113+
114+
CtorTwoDefaultArg();
115+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
116+
// CHECK-FIXES: CtorTwoDefaultArg give_me_a_name;
117+
118+
TCtorDefaultArg<int>();
119+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
120+
// CHECK-FIXES: TCtorDefaultArg<int> give_me_a_name;
121+
122+
TCtorDefaultArg<int>{};
123+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
124+
// CHECK-FIXES: TCtorDefaultArg<int> give_me_a_name;
125+
74126
templ<FooBar>();
75127
templ<Bar>();
76128

0 commit comments

Comments
 (0)