[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 21:23:28 PDT 2026


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

>From d7260fe29de6a9fa2e1b01495a8e50feaa6d22f8 Mon Sep 17 00:00:00 2001
From: Yuta Nakamura <yutanak6 at gmail.com>
Date: Sun, 19 Apr 2026 21:13:13 -0700
Subject: [PATCH] [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).

This fix excludes CXXOperatorCallExpr from the CallExpr match, except for
operator() (functor calls), which are treated like regular function calls.
This makes the check consistent: overloaded operators in operator form are
treated the same as built-in binary operators.

Fixes #192463, #192438, #192435.
---
 .../readability/RedundantParenthesesCheck.cpp |  4 ++-
 clang-tools-extra/docs/ReleaseNotes.rst       |  8 +++++
 .../readability/redundant-parentheses.cpp     | 33 +++++++++++++++++++
 3 files changed, 44 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..e52af57a49127 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -55,7 +55,9 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
                     parenExpr(), ConstantExpr,
                     declRefExpr(to(namedDecl(unless(
                         matchers::matchesAnyListedRegexName(AllowedDecls))))),
-                    memberExpr(), callExpr())),
+                    memberExpr(),
+                    callExpr(unless(cxxOperatorCallExpr(
+                        unless(hasOverloadedOperatorName("()")))))),
                 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..ec17ae71f9123 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -230,6 +230,14 @@ New check aliases
 Changes in existing checks
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+- Improved :doc:`readability-redundant-parentheses
+  <clang-tidy/checks/readability/redundant-parentheses>` check to fix a false
+  positive where parentheses around overloaded comparison operators (e.g.
+  ``iterator !=``, ``std::string >=``) were incorrectly flagged while
+  equivalent built-in operator expressions were not. Overloaded operators
+  written in operator form are now treated consistently with built-in binary
+  operators. Functor calls via ``operator()`` continue to be flagged.
+
 - Improved :doc:`bugprone-argument-comment
   <clang-tidy/checks/bugprone/argument-comment>` to also check for C++11
   inherited constructors.
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..212b60d424d23 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
@@ -99,6 +99,39 @@ struct Foo
   }
 };
 
+struct Iterator {
+  bool operator!=(const Iterator &) const;
+  bool operator>=(const Iterator &) const;
+};
+
+struct Functor {
+  bool operator()() const;
+};
+
+void overloadedOperators() {
+  Iterator it, end;
+
+  // Single parens around overloaded operator: no warning (consistent with
+  // built-in binary operators, which are not in the matcher).
+  if ((it != end)) {
+  }
+  if ((it >= end)) {
+  }
+
+  // Double parens: outer paren wraps a ParenExpr, so outer paren still warns.
+  if (((it != end))) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant parentheses around expression [readability-redundant-parentheses]
+    // CHECK-FIXES:    if ((it != end)) {
+  }
+
+  // Functor call via operator(): still warns (treated like a regular call).
+  Functor f{};
+  if ((f())) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant parentheses around expression [readability-redundant-parentheses]
+    // CHECK-FIXES:    if (f()) {
+  }
+}
+
 void memberExpr() {
   Foo foo{};
   if ((foo.x)) {



More information about the cfe-commits mailing list