[clang-tools-extra] [clang-tidy] add readability-redundant-parentheses (PR #159911)

Congcong Cai via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 25 07:51:07 PDT 2025


https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/159911

>From ad8fc039e1aea131c56c356e88c8c1a4c9afe737 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Fri, 19 Sep 2025 23:28:30 +0800
Subject: [PATCH 1/4] [clang-tidy] add readability-redundant-parentheses

This check wants to detect a common happened case that forgetting to
remove parenthese during modifying code.
---
 .../clang-tidy/readability/CMakeLists.txt     |  1 +
 .../readability/ReadabilityTidyModule.cpp     |  3 +
 .../readability/RedundantParenthesesCheck.cpp | 54 +++++++++++++++++
 .../readability/RedundantParenthesesCheck.h   | 31 ++++++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  5 ++
 .../docs/clang-tidy/checks/list.rst           |  1 +
 .../readability/redundant-parentheses.rst     | 29 ++++++++++
 .../readability/redundant-parentheses.cpp     | 58 +++++++++++++++++++
 8 files changed, 182 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp

diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 4b4c49d3b17d1..0d0641c4b22bf 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -44,6 +44,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
   RedundantDeclarationCheck.cpp
   RedundantFunctionPtrDereferenceCheck.cpp
   RedundantMemberInitCheck.cpp
+  RedundantParenthesesCheck.cpp
   RedundantPreprocessorCheck.cpp
   RedundantSmartptrGetCheck.cpp
   RedundantStringCStrCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index d01882dfc9daa..fcfac05b000e4 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -47,6 +47,7 @@
 #include "RedundantFunctionPtrDereferenceCheck.h"
 #include "RedundantInlineSpecifierCheck.h"
 #include "RedundantMemberInitCheck.h"
+#include "RedundantParenthesesCheck.h"
 #include "RedundantPreprocessorCheck.h"
 #include "RedundantSmartptrGetCheck.h"
 #include "RedundantStringCStrCheck.h"
@@ -138,6 +139,8 @@ class ReadabilityModule : public ClangTidyModule {
         "readability-redundant-function-ptr-dereference");
     CheckFactories.registerCheck<RedundantMemberInitCheck>(
         "readability-redundant-member-init");
+    CheckFactories.registerCheck<RedundantParenthesesCheck>(
+        "readability-redundant-parentheses");
     CheckFactories.registerCheck<RedundantPreprocessorCheck>(
         "readability-redundant-preprocessor");
     CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>(
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
new file mode 100644
index 0000000000000..6517f68216787
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -0,0 +1,54 @@
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantParenthesesCheck.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include <cassert>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+namespace {
+
+AST_MATCHER_P(ParenExpr, subExpr, ast_matchers::internal::Matcher<Expr>,
+              InnerMatcher) {
+  return InnerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
+}
+
+} // namespace
+
+void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      parenExpr(subExpr(anyOf(parenExpr(), integerLiteral(), floatLiteral(),
+                              characterLiteral(), cxxBoolLiteral(),
+                              stringLiteral(), declRefExpr())),
+                unless(
+                    // sizeof(...) is common used.
+                    hasParent(unaryExprOrTypeTraitExpr())))
+          .bind("dup"),
+      this);
+}
+
+void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup");
+  assert(PE);
+  const Expr *E = PE->getSubExpr();
+  if (PE->getLParen().isMacroID() || PE->getRParen().isMacroID() ||
+      E->getBeginLoc().isMacroID() || E->getEndLoc().isMacroID())
+    return;
+  diag(PE->getBeginLoc(), "redundant parentheses around expression")
+      << FixItHint::CreateRemoval(PE->getLParen())
+      << FixItHint::CreateRemoval(PE->getRParen());
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
new file mode 100644
index 0000000000000..8806fb391ba26
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
@@ -0,0 +1,31 @@
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPARENTHESESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPARENTHESESCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Detect redundant parentheses.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-parentheses.html
+class RedundantParenthesesCheck : public ClangTidyCheck {
+public:
+  RedundantParenthesesCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPARENTHESESCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a4652a7a54858..1dbacaf061b73 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -203,6 +203,11 @@ New checks
   Finds virtual function overrides with different visibility than the function
   in the base class.
 
+- New :doc:`readability-redundant-parentheses
+  <clang-tidy/checks/readability/redundant-parentheses>` check.
+
+  Detect redundant parentheses.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index e06849c419389..51d968895044c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -404,6 +404,7 @@ Clang-Tidy Checks
    :doc:`readability-redundant-function-ptr-dereference <readability/redundant-function-ptr-dereference>`, "Yes"
    :doc:`readability-redundant-inline-specifier <readability/redundant-inline-specifier>`, "Yes"
    :doc:`readability-redundant-member-init <readability/redundant-member-init>`, "Yes"
+   :doc:`readability-redundant-parentheses <readability/redundant-parentheses>`, "Yes"
    :doc:`readability-redundant-preprocessor <readability/redundant-preprocessor>`,
    :doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"
    :doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
new file mode 100644
index 0000000000000..09f9113b89cbd
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
@@ -0,0 +1,29 @@
+.. title:: clang-tidy - readability-redundant-parentheses
+
+readability-redundant-parentheses
+=================================
+
+Detect redundant parentheses.
+
+When modifying the code, one often forgets to remove the corresponding parentheses.
+This results in overly lengthy code. When the expression is complex, finding
+the matching parentheses becomes particularly difficult.
+
+Example
+-------
+
+.. code-block:: c++
+
+  (1);
+  ((a + 2)) * 3;
+  (a);
+  ("aaa");
+
+Currently this check does not take into account the precedence of operations.
+Even if the expression within the parentheses has a higher priority than that
+outside the parentheses, in other words, removing the parentheses will not
+affect the semantic.
+
+.. code-block:: c++
+
+  int a = (1 * 2) + 3; // no warning
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
new file mode 100644
index 0000000000000..017f22ec75721
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-parentheses.cpp
@@ -0,0 +1,58 @@
+// RUN: %check_clang_tidy %s readability-redundant-parentheses %t
+
+void parenExpr() {
+  1 + 1;
+  (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-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-MESSAGES: :[[@LINE-3]]:5: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    (1 + 1);
+}
+
+#define EXP (1 + 1)
+#define PAREN(e) (e)
+void parenExprWithMacro() {
+  EXP; // 1
+  (EXP); // 2
+  ((EXP)); // 3
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    (EXP); // 3
+  PAREN((1));
+}
+
+void constant() {
+  (1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    1;
+  (1.0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    1.0;
+  (true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    true;
+  (',');
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    ',';
+  ("v4");
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    "v4";
+}
+
+void declRefExpr(int a) {
+  (a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant parentheses around expression [readability-redundant-parentheses]
+  // CHECK-FIXES:    a;
+}
+
+void exceptions() {
+  sizeof(1);
+  alignof(2);
+}

>From 863331fc7a6ff0c8a3e68d355e65704964763413 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Mon, 22 Sep 2025 09:52:23 +0800
Subject: [PATCH 2/4] fix reviwe

---
 .../clang-tidy/readability/RedundantParenthesesCheck.cpp     | 1 -
 .../clang-tidy/readability/RedundantParenthesesCheck.h       | 5 ++++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index 6517f68216787..57b1dc949868a 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -1,4 +1,3 @@
-
 //===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
index 8806fb391ba26..43e244669fa2b 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
@@ -1,4 +1,3 @@
-
 //===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -11,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTPARENTHESESCHECK_H
 
 #include "../ClangTidyCheck.h"
+#include "clang/Basic/LangOptions.h"
 
 namespace clang::tidy::readability {
 
@@ -24,6 +24,9 @@ class RedundantParenthesesCheck : public ClangTidyCheck {
       : ClangTidyCheck(Name, Context) {}
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus | LangOpts.C99;
+  }
 };
 
 } // namespace clang::tidy::readability

>From 92db7842096a9850f1bb270e87d1249500965b04 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 23 Sep 2025 15:32:07 +0800
Subject: [PATCH 3/4] Update
 clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h

Co-authored-by: Victor Chernyakin <chernyakin.victor.j at outlook.com>
---
 .../clang-tidy/readability/RedundantParenthesesCheck.h          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
index 43e244669fa2b..9a0409b83fff3 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
@@ -17,7 +17,7 @@ namespace clang::tidy::readability {
 /// Detect redundant parentheses.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-parentheses.html
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-parentheses.html
 class RedundantParenthesesCheck : public ClangTidyCheck {
 public:
   RedundantParenthesesCheck(StringRef Name, ClangTidyContext *Context)

>From 42aab95490f6e6281a4b5f35d4ee34c584171826 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Thu, 25 Sep 2025 22:50:52 +0800
Subject: [PATCH 4/4] fix review

---
 .../readability/RedundantParenthesesCheck.cpp   | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index 57b1dc949868a..94ea823b18fc0 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -24,6 +24,12 @@ AST_MATCHER_P(ParenExpr, subExpr, ast_matchers::internal::Matcher<Expr>,
   return InnerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
 }
 
+AST_MATCHER(ParenExpr, isInMacro) {
+  const Expr *E = Node.getSubExpr();
+  return Node.getLParen().isMacroID() || Node.getRParen().isMacroID() ||
+         E->getBeginLoc().isMacroID() || E->getEndLoc().isMacroID();
+}
+
 } // namespace
 
 void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
@@ -31,20 +37,15 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
       parenExpr(subExpr(anyOf(parenExpr(), integerLiteral(), floatLiteral(),
                               characterLiteral(), cxxBoolLiteral(),
                               stringLiteral(), declRefExpr())),
-                unless(
-                    // sizeof(...) is common used.
-                    hasParent(unaryExprOrTypeTraitExpr())))
+                unless(anyOf(isInMacro(),
+                             // sizeof(...) is common used.
+                             hasParent(unaryExprOrTypeTraitExpr()))))
           .bind("dup"),
       this);
 }
 
 void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup");
-  assert(PE);
-  const Expr *E = PE->getSubExpr();
-  if (PE->getLParen().isMacroID() || PE->getRParen().isMacroID() ||
-      E->getBeginLoc().isMacroID() || E->getEndLoc().isMacroID())
-    return;
   diag(PE->getBeginLoc(), "redundant parentheses around expression")
       << FixItHint::CreateRemoval(PE->getLParen())
       << FixItHint::CreateRemoval(PE->getRParen());



More information about the cfe-commits mailing list