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

Part of #164125
Add a new option to ignore some decls.

---------

Co-authored-by: EugeneZelenko <eugene.zelenko@gmail.com>
This commit is contained in:
Congcong Cai 2025-10-31 10:51:58 +08:00 committed by GitHub
parent bf99f6693e
commit e65d52ab5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 6 deletions

View File

@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "RedundantParenthesesCheck.h"
#include "../utils/Matchers.h"
#include "../utils/OptionsUtils.h"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
@ -32,15 +34,30 @@ 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(),
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);
}

View File

@ -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

View File

@ -27,3 +27,16 @@ affect the semantics.
.. code-block:: c++
int a = (1 * 2) + 3; // no warning
Options
-------
.. option:: AllowedDecls
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
macro. For example, ``std::max`` and ``max`` macro. A workaround to distinguish
them is adding parentheses around functions to prevent function-like macro.

View File

@ -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);
}