Skip to content

Commit feb7b19

Browse files
authored
[clang-analysis]Fix false positive in mutation check when using pointer to member function (llvm#66846)
Fixes: llvm#66204
1 parent 7421dd5 commit feb7b19

File tree

5 files changed

+69
-3
lines changed

5 files changed

+69
-3
lines changed

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ Changes in existing checks
246246
customizable namespace. This further allows for testing the libc when the
247247
system-libc is also LLVM's libc.
248248

249+
- Improved :doc:`misc-const-correctness
250+
<clang-tidy/checks/misc/const-correctness>` check to avoid false positive when
251+
using pointer to member function.
252+
249253
- Improved :doc:`misc-include-cleaner
250254
<clang-tidy/checks/misc/include-cleaner>` check by adding option
251255
`DeduplicateFindings` to output one finding per symbol occurrence.

clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,3 +976,16 @@ void auto_usage_variants() {
976976
auto &auto_td1 = auto_td0;
977977
auto *auto_td2 = &auto_td0;
978978
}
979+
980+
using PointerToMemberFunction = int (Value::*)();
981+
void member_pointer(Value &x, PointerToMemberFunction m) {
982+
Value &member_pointer_tmp = x;
983+
(member_pointer_tmp.*m)();
984+
}
985+
986+
using PointerToConstMemberFunction = int (Value::*)() const;
987+
void member_pointer_const(Value &x, PointerToConstMemberFunction m) {
988+
Value &member_pointer_tmp = x;
989+
// CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'member_pointer_tmp' of type 'Value &' can be declared 'const'
990+
(member_pointer_tmp.*m)();
991+
}

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,9 @@ Static Analyzer
502502
bitwise shift operators produce undefined behavior (because some operand is
503503
negative or too large).
504504

505+
- Fix false positive in mutation check when using pointer to member function.
506+
(`#66204: <https://github.com/llvm/llvm-project/issues/66204>`_).
507+
505508
- The ``alpha.security.taint.TaintPropagation`` checker no longer propagates
506509
taint on ``strlen`` and ``strnlen`` calls, unless these are marked
507510
explicitly propagators in the user-provided taint configuration file.

clang/lib/Analysis/ExprMutationAnalyzer.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,20 @@ AST_MATCHER(CXXTypeidExpr, isPotentiallyEvaluated) {
100100
return Node.isPotentiallyEvaluated();
101101
}
102102

103+
AST_MATCHER(CXXMemberCallExpr, isConstCallee) {
104+
const Decl *CalleeDecl = Node.getCalleeDecl();
105+
const auto *VD = dyn_cast_or_null<ValueDecl>(CalleeDecl);
106+
if (!VD)
107+
return false;
108+
const QualType T = VD->getType().getCanonicalType();
109+
const auto *MPT = dyn_cast<MemberPointerType>(T);
110+
const auto *FPT = MPT ? cast<FunctionProtoType>(MPT->getPointeeType())
111+
: dyn_cast<FunctionProtoType>(T);
112+
if (!FPT)
113+
return false;
114+
return FPT->isConst();
115+
}
116+
103117
AST_MATCHER_P(GenericSelectionExpr, hasControllingExpr,
104118
ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
105119
if (Node.isTypePredicate())
@@ -274,8 +288,8 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
274288
const auto NonConstMethod = cxxMethodDecl(unless(isConst()));
275289

276290
const auto AsNonConstThis = expr(anyOf(
277-
cxxMemberCallExpr(callee(NonConstMethod),
278-
on(canResolveToExpr(equalsNode(Exp)))),
291+
cxxMemberCallExpr(on(canResolveToExpr(equalsNode(Exp))),
292+
unless(isConstCallee())),
279293
cxxOperatorCallExpr(callee(NonConstMethod),
280294
hasArgument(0, canResolveToExpr(equalsNode(Exp)))),
281295
// In case of a templated type, calling overloaded operators is not
@@ -391,7 +405,9 @@ const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) {
391405
match(findAll(expr(anyOf(memberExpr(hasObjectExpression(
392406
canResolveToExpr(equalsNode(Exp)))),
393407
cxxDependentScopeMemberExpr(hasObjectExpression(
394-
canResolveToExpr(equalsNode(Exp))))))
408+
canResolveToExpr(equalsNode(Exp)))),
409+
binaryOperator(hasOperatorName(".*"),
410+
hasLHS(equalsNode(Exp)))))
395411
.bind(NodeID<Expr>::value)),
396412
Stm, Context);
397413
return findExprMutation(MemberExprs);

clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,36 @@ TEST(ExprMutationAnalyzerTest, TypeDependentMemberCall) {
284284
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.push_back(T())"));
285285
}
286286

287+
TEST(ExprMutationAnalyzerTest, MemberPointerMemberCall) {
288+
{
289+
const auto AST =
290+
buildASTFromCode("struct X {};"
291+
"using T = int (X::*)();"
292+
"void f(X &x, T m) { X &ref = x; (ref.*m)(); }");
293+
const auto Results =
294+
match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext());
295+
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(ref .* m)()"));
296+
}
297+
{
298+
const auto AST =
299+
buildASTFromCode("struct X {};"
300+
"using T = int (X::*)();"
301+
"void f(X &x, T const m) { X &ref = x; (ref.*m)(); }");
302+
const auto Results =
303+
match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext());
304+
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(ref .* m)()"));
305+
}
306+
{
307+
const auto AST =
308+
buildASTFromCode("struct X {};"
309+
"using T = int (X::*)() const;"
310+
"void f(X &x, T m) { X &ref = x; (ref.*m)(); }");
311+
const auto Results =
312+
match(withEnclosingCompound(declRefTo("ref")), AST->getASTContext());
313+
EXPECT_FALSE(isMutated(Results, AST.get()));
314+
}
315+
}
316+
287317
// Section: overloaded operators
288318

289319
TEST(ExprMutationAnalyzerTest, NonConstOperator) {

0 commit comments

Comments
 (0)