[clang-tools-extra] [clang-tidy] Fix false positive in readability-redundant-parentheses … (PR #192827)

Yuta Nakamura via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 19 11:17:03 PDT 2026


https://github.com/nakasan617 updated https://github.com/llvm/llvm-project/pull/192827

>From 30b41467e5e8a86acd2495db0a7615f4b698b645 Mon Sep 17 00:00:00 2001
From: Yuta Nakamura <yutanak6 at gmail.com>
Date: Sat, 18 Apr 2026 21:43:48 -0700
Subject: [PATCH 1/4] [clang-tidy] Fix false positive in
 readability-redundant-parentheses for overloaded operators

Overloaded comparison operators (e.g. iterator !=, std::string >=) are
represented as CXXOperatorCallExpr, a subclass of CallExpr. The matcher
previously matched all CallExpr, causing spurious warnings for parenthesized
overloaded-operator expressions while silently accepting equivalent built-in
operator expressions (e.g. int == int). Exclude CXXOperatorCallExpr from the
CallExpr match to make the behavior consistent.

Fixes: #192463, #192438, #192435
---
 .../readability/RedundantParenthesesCheck.cpp |  3 ++-
 .../readability/redundant-parentheses.cpp     | 20 +++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index 9b3948a1c50c0..a1500ad80869e 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -55,7 +55,8 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
                     parenExpr(), ConstantExpr,
                     declRefExpr(to(namedDecl(unless(
                         matchers::matchesAnyListedRegexName(AllowedDecls))))),
-                    memberExpr(), callExpr())),
+                    memberExpr(),
+                    callExpr(unless(cxxOperatorCallExpr())))),
                 unless(anyOf(isInMacro(),
                              // sizeof(...) is common used.
                              hasParent(unaryExprOrTypeTraitExpr()))))
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
index 9a8a0d4d73483..d080f3f5a3f56 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
@@ -121,3 +121,23 @@ void memberExpr() {
    // CHECK-FIXES:    if (foo.fooBar().z) {
   }
 }
+
+struct Iterator {
+  bool operator!=(const Iterator &) const;
+  bool operator==(const Iterator &) const;
+  bool operator>=(const Iterator &) const;
+};
+
+// Overloaded operators look like binary expressions to readers; no warning.
+bool overloadedOperatorNoWarn(Iterator it, Iterator end) {
+  if ((it != end))
+    return true;
+  if ((it == end))
+    return false;
+  return (it >= end);
+}
+
+// Built-in comparison operators also produce no warning.
+bool builtinComparisonNoWarn(int i) {
+  return (i == 0);
+}

>From ce993a2e9757260e012371e6cc9fad46be662501 Mon Sep 17 00:00:00 2001
From: Yuta Nakamura <yutanak6 at gmail.com>
Date: Sat, 18 Apr 2026 22:10:14 -0700
Subject: [PATCH 2/4] [clang-tidy] Fix clang-format: keep memberExpr and
 callExpr on one line

---
 .../clang-tidy/readability/RedundantParenthesesCheck.cpp       | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index a1500ad80869e..c177c07b95a75 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -55,8 +55,7 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
                     parenExpr(), ConstantExpr,
                     declRefExpr(to(namedDecl(unless(
                         matchers::matchesAnyListedRegexName(AllowedDecls))))),
-                    memberExpr(),
-                    callExpr(unless(cxxOperatorCallExpr())))),
+                    memberExpr(), callExpr(unless(cxxOperatorCallExpr())))),
                 unless(anyOf(isInMacro(),
                              // sizeof(...) is common used.
                              hasParent(unaryExprOrTypeTraitExpr()))))

>From b406b2de06e139d4faab0fb928ccc288d0ff438d Mon Sep 17 00:00:00 2001
From: Yuta Nakamura <yutanak6 at gmail.com>
Date: Sun, 19 Apr 2026 10:39:32 -0700
Subject: [PATCH 3/4] [clang-tidy] Fix inconsistency in
 readability-redundant-parentheses for binary operators

Built-in binary operators (e.g. i == 0) were not flagged while overloaded
operators (e.g. iterator !=) were, because the matcher only covered CallExpr.
Add binaryOperator() to the matcher so both cases warn consistently.

Fixes: #192463, #192438, #192435
---
 .../readability/RedundantParenthesesCheck.cpp |  2 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |  6 ++++++
 .../readability/redundant-parentheses.cpp     | 19 ++++++++++++-------
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index c177c07b95a75..f353b5e876891 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -55,7 +55,7 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
                     parenExpr(), ConstantExpr,
                     declRefExpr(to(namedDecl(unless(
                         matchers::matchesAnyListedRegexName(AllowedDecls))))),
-                    memberExpr(), callExpr(unless(cxxOperatorCallExpr())))),
+                    memberExpr(), callExpr(), binaryOperator())),
                 unless(anyOf(isInMacro(),
                              // sizeof(...) is common used.
                              hasParent(unaryExprOrTypeTraitExpr()))))
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 95ed0061d654c..ed173f9a81344 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -530,6 +530,12 @@ Changes in existing checks
   - Fixed a false positive in array subscript expressions where the types are
     not yet resolved.
 
+- Improved :doc:`readability-redundant-parentheses
+  <clang-tidy/checks/readability/redundant-parentheses>` check to consistently
+  warn for parenthesized built-in binary operator expressions (e.g.
+  ``(i == 0)``), matching the existing behavior for overloaded operator
+  expressions.
+
 - Improved :doc:`readability-redundant-member-init
   <clang-tidy/checks/readability/redundant-member-init>` check by adding an
   `IgnoreMacros` option to suppress warnings when the initializer involves
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
index d080f3f5a3f56..59b88fb753be4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
@@ -128,16 +128,21 @@ struct Iterator {
   bool operator>=(const Iterator &) const;
 };
 
-// Overloaded operators look like binary expressions to readers; no warning.
-bool overloadedOperatorNoWarn(Iterator it, Iterator end) {
+// Both overloaded and built-in operators warn: parens are redundant.
+bool operatorWarn(Iterator it, Iterator end, int i) {
   if ((it != end))
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant parentheses around expression [readability-redundant-parentheses]
+    // CHECK-FIXES:    if (it != end)
     return true;
   if ((it == end))
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant parentheses around expression [readability-redundant-parentheses]
+    // CHECK-FIXES:    if (it == end)
     return false;
+  if ((i == 0))
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant parentheses around expression [readability-redundant-parentheses]
+    // CHECK-FIXES:    if (i == 0)
+    return true;
   return (it >= end);
-}
-
-// Built-in comparison operators also produce no warning.
-bool builtinComparisonNoWarn(int i) {
-  return (i == 0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    return it >= end;
 }

>From 942665c2cbdebd20d53d8554b83f521c076a0faa Mon Sep 17 00:00:00 2001
From: Yuta Nakamura <yutanak6 at gmail.com>
Date: Sun, 19 Apr 2026 11:07:32 -0700
Subject: [PATCH 4/4] [clang-tidy] Update redundant-parentheses tests for
 binaryOperator coverage

---
 .../checkers/readability/redundant-parentheses.cpp    | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
index 59b88fb753be4..1c9f0297742dd 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
@@ -3,18 +3,23 @@
 void parenExpr() {
   1 + 1;
   (1 + 1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    1 + 1;
   ((1 + 1));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
-  // CHECK-FIXES:    (1 + 1);
+  // CHECK-MESSAGES: :[[@LINE-2]]:4: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    1 + 1;
   (((1 + 1)));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
   // CHECK-MESSAGES: :[[@LINE-2]]:4: warning: redundant parentheses around expression [readability-redundant-parentheses]
-  // CHECK-FIXES:    (1 + 1);
+  // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    1 + 1;
   ((((1 + 1))));
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
   // CHECK-MESSAGES: :[[@LINE-2]]:4: warning: redundant parentheses around expression [readability-redundant-parentheses]
   // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant parentheses around expression [readability-redundant-parentheses]
-  // CHECK-FIXES:    (1 + 1);
+  // CHECK-MESSAGES: :[[@LINE-4]]:6: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    1 + 1;
 }
 
 #define EXP (1 + 1)



More information about the cfe-commits mailing list