[clang] 60afce2 - [clang-tidy] fix fp when modifying variant by ``operator[]`` with template in parameters (#128407)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 2 03:39:53 PST 2025
Author: Congcong Cai
Date: 2025-03-02T19:39:49+08:00
New Revision: 60afce2df97d1f8fd78405a039e8e818c5154565
URL: https://github.com/llvm/llvm-project/commit/60afce2df97d1f8fd78405a039e8e818c5154565
DIFF: https://github.com/llvm/llvm-project/commit/60afce2df97d1f8fd78405a039e8e818c5154565.diff
LOG: [clang-tidy] fix fp when modifying variant by ``operator[]`` with template in parameters (#128407)
`ArraySubscriptExpr` can switch base and idx. For dependent array
subscript access, we should check both base and idx conservatively.
Added:
Modified:
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp
clang/lib/Analysis/ExprMutationAnalyzer.cpp
clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 07a79d6bbe807..71edb704b49d6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -122,7 +122,8 @@ Changes in existing checks
- Improved :doc:`misc-const-correctness
<clang-tidy/checks/misc/const-correctness>` check by adding the option
`AllowedTypes`, that excludes specified types from const-correctness
- checking.
+ checking and fixing false positives when modifying variant by ``operator[]``
+ with template in parameters.
- Improved :doc:`misc-redundant-expression
<clang-tidy/checks/misc/redundant-expression>` check by providing additional
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp
index 5efb64bca2374..654deead4efc8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-values.cpp
@@ -998,3 +998,11 @@ void member_pointer_const(Value &x, PointerToConstMemberFunction m) {
// CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'member_pointer_tmp' of type 'Value &' can be declared 'const'
(member_pointer_tmp.*m)();
}
+
+namespace gh127776_false_positive {
+template <class T> struct vector { T &operator[](int t); };
+template <typename T> void f() {
+ vector<int> x;
+ x[T{}] = 3;
+}
+} // namespace gh127776_false_positive
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 8944343484e58..823d7543f085f 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -80,6 +80,17 @@ static bool canExprResolveTo(const Expr *Source, const Expr *Target) {
namespace {
+// `ArraySubscriptExpr` can switch base and idx, e.g. `a[4]` is the same as
+// `4[a]`. When type is dependent, we conservatively assume both sides are base.
+AST_MATCHER_P(ArraySubscriptExpr, hasBaseConservative,
+ ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+ if (Node.isTypeDependent()) {
+ return InnerMatcher.matches(*Node.getLHS(), Finder, Builder) ||
+ InnerMatcher.matches(*Node.getRHS(), Finder, Builder);
+ }
+ return InnerMatcher.matches(*Node.getBase(), Finder, Builder);
+}
+
AST_MATCHER(Type, isDependentType) { return Node.isDependentType(); }
AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) {
@@ -513,8 +524,8 @@ ExprMutationAnalyzer::Analyzer::findArrayElementMutation(const Expr *Exp) {
// Check whether any element of an array is mutated.
const auto SubscriptExprs = match(
findAll(arraySubscriptExpr(
- anyOf(hasBase(canResolveToExpr(Exp)),
- hasBase(implicitCastExpr(allOf(
+ anyOf(hasBaseConservative(canResolveToExpr(Exp)),
+ hasBaseConservative(implicitCastExpr(allOf(
hasCastKind(CK_ArrayToPointerDecay),
hasSourceExpression(canResolveToExpr(Exp)))))))
.bind(NodeID<Expr>::value)),
@@ -716,7 +727,8 @@ ExprMutationAnalyzer::Analyzer::findPointeeValueMutation(const Expr *Exp) {
unaryOperator(hasOperatorName("*"),
hasUnaryOperand(canResolveToExprPointee(Exp))),
// deref by []
- arraySubscriptExpr(hasBase(canResolveToExprPointee(Exp)))))
+ arraySubscriptExpr(
+ hasBaseConservative(canResolveToExprPointee(Exp)))))
.bind(NodeID<Expr>::value))),
Stm, Context);
return findExprMutation(Matches);
diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index cc277d56b37a2..720999207083d 100644
--- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -870,6 +870,19 @@ TEST(ExprMutationAnalyzerTest, TemplateWithArrayToPointerDecay) {
EXPECT_THAT(mutatedBy(ResultsY, AST.get()), ElementsAre("y"));
}
+TEST(ExprMutationAnalyzerTest, T1) {
+ const auto AST = buildASTFromCodeWithArgs(
+ "template <class T> struct vector { T &operator[](int t); };"
+ "template <typename T> void func() {"
+ " vector<int> x;"
+ " x[T{}] = 3;"
+ "}",
+ {"-fno-delayed-template-parsing"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
// section: special case: all created references are non-mutating themself
// and therefore all become 'const'/the value is not modified!
More information about the cfe-commits
mailing list