[clang-tools-extra] [clang-tidy][readability-redundant-parentheses] add option to prevent widely used work around (PR #164827)

Congcong Cai via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 27 20:03:17 PDT 2025


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

>From 525b01535ccde73b341231fccf4d493fc1433914 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Thu, 23 Oct 2025 22:36:40 +0800
Subject: [PATCH 1/4] [clang-tidy][readability-redundant-parentheses] add
 option to prevent widely used work around

Fixed: #164125
Add a new option to ignore some decls.

Because it is a new check in this version, no release note needs to be updated.
---
 .../readability/RedundantParenthesesCheck.cpp | 22 +++++++++++++++++++
 .../readability/RedundantParenthesesCheck.h   |  7 ++++--
 .../readability/redundant-parentheses.rst     | 13 +++++++++++
 .../readability/redundant-parentheses.cpp     |  9 ++++++++
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index 0ab59fff39d88..2b5cf12603609 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RedundantParenthesesCheck.h"
+#include "../utils/OptionsUtils.h"
 #include "clang/AST/Expr.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
@@ -32,6 +33,18 @@ AST_MATCHER(ParenExpr, isInMacro) {
 
 } // namespace
 
+RedundantParenthesesCheck::RedundantParenthesesCheck(StringRef Name,
+                                                     ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      AllowedDecls(utils::options::parseStringList(
+          Options.get("AllowedDecls", "std::max;std::min"))) {}
+
+void RedundantParenthesesCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "AllowedDecls",
+                utils::options::serializeStringList(AllowedDecls));
+}
+
 void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
   const auto ConstantExpr =
       expr(anyOf(integerLiteral(), floatLiteral(), characterLiteral(),
@@ -47,6 +60,15 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
 
 void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup");
+  if (auto *DRE = dyn_cast<DeclRefExpr>(PE->getSubExpr())) {
+    const std::string Name = DRE->getDecl()->getQualifiedNameAsString();
+    llvm::errs() << Name << "\n";
+    bool Allowed = llvm::any_of(AllowedDecls, [&Name](const llvm::Regex &NM) {
+      return NM.isValid() && NM.match(Name);
+    });
+    if (Allowed)
+      return;
+  }
   diag(PE->getBeginLoc(), "redundant parentheses around expression")
       << FixItHint::CreateRemoval(PE->getLParen())
       << FixItHint::CreateRemoval(PE->getRParen());
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
index 9a0409b83fff3..2638a09730f7e 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.h
@@ -20,13 +20,16 @@ namespace clang::tidy::readability {
 /// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-parentheses.html
 class RedundantParenthesesCheck : public ClangTidyCheck {
 public:
-  RedundantParenthesesCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+  RedundantParenthesesCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   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;
   }
+
+private:
+  const std::vector<StringRef> AllowedDecls;
 };
 
 } // namespace clang::tidy::readability
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
index 23d975e646490..66b31fae2f2ed 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
@@ -27,3 +27,16 @@ affect the semantics.
 .. code-block:: c++
 
   int a = (1 * 2) + 3; // no warning
+
+Options
+-------
+
+.. option:: AllowedDecls
+
+  A semicolon-separated list of names of declarations included variables and
+  functions to ignore when the parenthese around it.
+  The default is an `std::max;std::min`.
+  
+  Some std library functions may have the same name as widely used function-like
+  macro. For example, ``std::max`` and ``max`` macro. A work around to distinguish
+  them is adding parenthese around functions to prevent function-like macro.
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 926cb118c77cf..c77608c66469c 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
@@ -62,3 +62,12 @@ void exceptions() {
   // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant parentheses around expression [readability-redundant-parentheses]
   // CHECK-FIXES:    alignof(3);
 }
+
+namespace std {
+  template<class T> T max(T, T);
+  template<class T> T min(T, T);
+} // namespace std
+void ignoreStdMaxMin() {
+  (std::max)(1,2);
+  (std::min)(1,2);
+}

>From 8f84ad5ce977673e442304d7aa05d3b11dab5cbb Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Fri, 24 Oct 2025 10:25:25 +0800
Subject: [PATCH 2/4] Update
 clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp

---
 .../clang-tidy/readability/RedundantParenthesesCheck.cpp         | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index 2b5cf12603609..f653881f93769 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -62,7 +62,6 @@ void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup");
   if (auto *DRE = dyn_cast<DeclRefExpr>(PE->getSubExpr())) {
     const std::string Name = DRE->getDecl()->getQualifiedNameAsString();
-    llvm::errs() << Name << "\n";
     bool Allowed = llvm::any_of(AllowedDecls, [&Name](const llvm::Regex &NM) {
       return NM.isValid() && NM.match(Name);
     });

>From 5e37c831304d9f10b75898024c0ca1b331e68868 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Fri, 24 Oct 2025 12:38:42 +0800
Subject: [PATCH 3/4] fix review

---
 .../readability/RedundantParenthesesCheck.cpp          |  7 ++++---
 .../checks/readability/redundant-parentheses.rst       | 10 +++++-----
 2 files 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 f653881f93769..9a129a3f63b92 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -62,9 +62,10 @@ void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup");
   if (auto *DRE = dyn_cast<DeclRefExpr>(PE->getSubExpr())) {
     const std::string Name = DRE->getDecl()->getQualifiedNameAsString();
-    bool Allowed = llvm::any_of(AllowedDecls, [&Name](const llvm::Regex &NM) {
-      return NM.isValid() && NM.match(Name);
-    });
+    const bool Allowed =
+        llvm::any_of(AllowedDecls, [&Name](const llvm::Regex &NM) {
+          return NM.isValid() && NM.match(Name);
+        });
     if (Allowed)
       return;
   }
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
index 66b31fae2f2ed..4802a95a52534 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
@@ -33,10 +33,10 @@ Options
 
 .. option:: AllowedDecls
 
-  A semicolon-separated list of names of declarations included variables and
-  functions to ignore when the parenthese around it.
+  A semicolon-separated list of names of declarations to ignore when the
+  parentheses are around. Declarations can include variables or functions.
   The default is an `std::max;std::min`.
   
-  Some std library functions may have the same name as widely used function-like
-  macro. For example, ``std::max`` and ``max`` macro. A work around to distinguish
-  them is adding parenthese around functions to prevent function-like macro.
+  Some STL library functions may have the same name as widely used function-like
+  macro. For example, ``std::max`` and ``max`` macro. A workaround to distinguish
+  them is adding parentheses around functions to prevent function-like macro.

>From 50e451f56b91d491c87f82ec5e89d42f5c7c566e Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 28 Oct 2025 11:03:05 +0800
Subject: [PATCH 4/4] fix reviwe

---
 .../readability/RedundantParenthesesCheck.cpp | 21 +++++++------------
 .../readability/redundant-parentheses.rst     |  5 +++--
 2 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
index 9a129a3f63b92..874b9618bd882 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantParenthesesCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RedundantParenthesesCheck.h"
+#include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/AST/Expr.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -50,25 +51,19 @@ void RedundantParenthesesCheck::registerMatchers(MatchFinder *Finder) {
       expr(anyOf(integerLiteral(), floatLiteral(), characterLiteral(),
                  cxxBoolLiteral(), stringLiteral(), cxxNullPtrLiteralExpr()));
   Finder->addMatcher(
-      parenExpr(subExpr(anyOf(parenExpr(), ConstantExpr, declRefExpr())),
-                unless(anyOf(isInMacro(),
-                             // sizeof(...) is common used.
-                             hasParent(unaryExprOrTypeTraitExpr()))))
+      parenExpr(
+          subExpr(anyOf(parenExpr(), ConstantExpr,
+                        declRefExpr(to(namedDecl(unless(
+                            matchers::matchesAnyListedName(AllowedDecls))))))),
+          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");
-  if (auto *DRE = dyn_cast<DeclRefExpr>(PE->getSubExpr())) {
-    const std::string Name = DRE->getDecl()->getQualifiedNameAsString();
-    const bool Allowed =
-        llvm::any_of(AllowedDecls, [&Name](const llvm::Regex &NM) {
-          return NM.isValid() && NM.match(Name);
-        });
-    if (Allowed)
-      return;
-  }
   diag(PE->getBeginLoc(), "redundant parentheses around expression")
       << FixItHint::CreateRemoval(PE->getLParen())
       << FixItHint::CreateRemoval(PE->getRParen());
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
index 4802a95a52534..491983d34cd83 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-parentheses.rst
@@ -33,8 +33,9 @@ Options
 
 .. option:: AllowedDecls
 
-  A semicolon-separated list of names of declarations to ignore when the
-  parentheses are around. Declarations can include variables or functions.
+  Semicolon-separated list of regular expressions matching names of declarations
+  to ignore when the parentheses are around. Declarations can include variables
+  or functions.
   The default is an `std::max;std::min`.
   
   Some STL library functions may have the same name as widely used function-like



More information about the cfe-commits mailing list