Skip to content

Commit e90ab99

Browse files
committed
[clang-tidy] Add C++ member function support to user-defined bugprone-unsafe-functions matches
1 parent 86fd4d4 commit e90ab99

File tree

3 files changed

+53
-12
lines changed

3 files changed

+53
-12
lines changed

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

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,32 @@ void UnsafeFunctionsCheck::registerMatchers(MatchFinder *Finder) {
256256
.bind(CustomFunctionNamesId)))
257257
.bind(DeclRefId),
258258
this);
259+
// C++ member calls do not contain a DeclRefExpr to the function decl.
260+
// Instead, they contain a MemberExpr that refers to the decl.
261+
Finder->addMatcher(memberExpr(member(functionDecl(CustomFunctionsMatcher)
262+
.bind(CustomFunctionNamesId)))
263+
.bind(DeclRefId),
264+
this);
259265
}
260266
}
261267

262268
void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
263-
const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>(DeclRefId);
264-
const auto *FuncDecl = cast<FunctionDecl>(DeclRef->getDecl());
265-
assert(DeclRef && FuncDecl && "No valid matched node in check()");
269+
const Expr *SourceExpr;
270+
const FunctionDecl *FuncDecl;
271+
272+
if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>(DeclRefId)) {
273+
SourceExpr = DeclRef;
274+
FuncDecl = cast<FunctionDecl>(DeclRef->getDecl());
275+
} else if (const auto *Member =
276+
Result.Nodes.getNodeAs<MemberExpr>(DeclRefId)) {
277+
SourceExpr = Member;
278+
FuncDecl = cast<FunctionDecl>(Member->getMemberDecl());
279+
} else {
280+
llvm_unreachable("No valid matched node in check()");
281+
return;
282+
}
283+
284+
assert(SourceExpr && FuncDecl && "No valid matched node in check()");
266285

267286
// Only one of these are matched at a time.
268287
const auto *AnnexK = Result.Nodes.getNodeAs<FunctionDecl>(
@@ -286,14 +305,15 @@ void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
286305
Entry.Reason.empty() ? "is marked as unsafe" : Entry.Reason.c_str();
287306

288307
if (Entry.Replacement.empty()) {
289-
diag(DeclRef->getExprLoc(), "function %0 %1; it should not be used")
308+
diag(SourceExpr->getExprLoc(),
309+
"function %0 %1; it should not be used")
290310
<< FuncDecl << Reason << Entry.Replacement
291-
<< DeclRef->getSourceRange();
311+
<< SourceExpr->getSourceRange();
292312
} else {
293-
diag(DeclRef->getExprLoc(),
313+
diag(SourceExpr->getExprLoc(),
294314
"function %0 %1; '%2' should be used instead")
295315
<< FuncDecl << Reason << Entry.Replacement
296-
<< DeclRef->getSourceRange();
316+
<< SourceExpr->getSourceRange();
297317
}
298318

299319
return;
@@ -323,9 +343,9 @@ void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
323343
if (!ReplacementFunctionName)
324344
return;
325345

326-
diag(DeclRef->getExprLoc(), "function %0 %1; '%2' should be used instead")
346+
diag(SourceExpr->getExprLoc(), "function %0 %1; '%2' should be used instead")
327347
<< FuncDecl << getRationaleFor(FunctionName)
328-
<< ReplacementFunctionName.value() << DeclRef->getSourceRange();
348+
<< ReplacementFunctionName.value() << SourceExpr->getSourceRange();
329349
}
330350

331351
void UnsafeFunctionsCheck::registerPPCallbacks(

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ Changes in existing checks
192192

193193
- Improved :doc:`bugprone-unsafe-functions
194194
<clang-tidy/checks/bugprone/unsafe-functions>` check to allow specifying
195-
additional functions to match.
195+
additional functions to match, including C++ member functions.
196196

197197
- Improved :doc:`bugprone-use-after-move
198198
<clang-tidy/checks/bugprone/use-after-move>` to avoid triggering on

clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom-regex.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
// RUN: %check_clang_tidy -check-suffix=NON-STRICT-REGEX %s bugprone-unsafe-functions %t --\
2-
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '::name_match,replacement,is a qualname match;^::prefix_match,,is matched on qualname prefix'}}"
2+
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '::name_match,replacement,is a qualname match;^::prefix_match,,is matched on qualname prefix;^::S::member_match_,,is matched on a C++ class member'}}"
33
// RUN: %check_clang_tidy -check-suffix=STRICT-REGEX %s bugprone-unsafe-functions %t --\
4-
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '^name_match$,replacement,is matched on function name only;^::prefix_match$,,is a full qualname match'}}"
4+
// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '^name_match$,replacement,is matched on function name only;^::prefix_match$,,is a full qualname match;^::S::member_match_1$,,is matched on a C++ class member'}}"
55

66
void name_match();
77
void prefix_match();
88

9+
struct S {
10+
static void member_match_1() {}
11+
void member_match_2() {}
12+
};
13+
914
namespace regex_test {
1015
void name_match();
1116
void prefix_match();
@@ -42,3 +47,19 @@ void f1() {
4247
// CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match_regex' is matched on qualname prefix; it should not be used
4348
// no-warning STRICT-REGEX
4449
}
50+
51+
void f2() {
52+
S s;
53+
54+
S::member_match_1();
55+
// CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'member_match_1' is matched on a C++ class member; it should not be used
56+
// CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'member_match_1' is matched on a C++ class member; it should not be used
57+
58+
s.member_match_1();
59+
// CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:5: warning: function 'member_match_1' is matched on a C++ class member; it should not be used
60+
// CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:5: warning: function 'member_match_1' is matched on a C++ class member; it should not be used
61+
62+
s.member_match_2();
63+
// CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:5: warning: function 'member_match_2' is matched on a C++ class member; it should not be used
64+
// no-warning STRICT-REGEX
65+
}

0 commit comments

Comments
 (0)