clang-tools 24.0.0git
RedundantParenthesesCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "../utils/Matchers.h"
12#include "clang/AST/Expr.h"
13#include "clang/AST/TypeLoc.h"
14#include "clang/ASTMatchers/ASTMatchFinder.h"
15#include "clang/ASTMatchers/ASTMatchers.h"
16#include "clang/ASTMatchers/ASTMatchersMacros.h"
17#include "clang/Lex/Lexer.h"
18#include <cassert>
19
20using namespace clang::ast_matchers;
21
23
24namespace {
25
26AST_MATCHER_P(ParenExpr, subExpr, ast_matchers::internal::Matcher<Expr>,
27 InnerMatcher) {
28 return InnerMatcher.matches(*Node.getSubExpr(), Finder, Builder);
29}
30
31AST_MATCHER(ParenExpr, isInMacro) {
32 const Expr *E = Node.getSubExpr();
33 return Node.getLParen().isMacroID() || Node.getRParen().isMacroID() ||
34 E->getBeginLoc().isMacroID() || E->getEndLoc().isMacroID();
35}
36
37AST_MATCHER(ParenExpr, isWritten) {
38 return Node.getLParen() != Node.getRParen();
39}
40
41AST_MATCHER(TypeLoc, isTypeOfExprTypeLoc) {
42 return !Node.getUnqualifiedLoc().getAs<TypeOfExprTypeLoc>().isNull();
43}
44
45AST_MATCHER(AutoType, isDecltypeAuto) { return Node.isDecltypeAuto(); }
46
47} // namespace
48
49static FixItHint createSpacedRemoval(SourceLocation Loc,
50 const SourceManager &SM,
51 const LangOptions &LangOpts) {
52 if (Loc.isValid() && !Loc.isMacroID()) {
53 const auto LocInfo = SM.getDecomposedLoc(Loc);
54 bool Invalid = false;
55 StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
56 if (!Invalid && LocInfo.second > 0 && LocInfo.second + 1 < Buffer.size() &&
57 Lexer::isAsciiIdentifierContinueChar(Buffer[LocInfo.second - 1],
58 LangOpts) &&
59 Lexer::isAsciiIdentifierContinueChar(Buffer[LocInfo.second + 1],
60 LangOpts))
61 return FixItHint::CreateReplacement(SourceRange(Loc, Loc), " ");
62 }
63 return FixItHint::CreateRemoval(Loc);
64}
65
67 ClangTidyContext *Context)
68 : ClangTidyCheck(Name, Context),
69 AllowedDecls(utils::options::parseStringList(
70 Options.get("AllowedDecls", "std::max;std::min"))) {}
71
74 Options.store(Opts, "AllowedDecls",
76}
77
79 const auto ConstantExpr =
80 expr(anyOf(integerLiteral(), floatLiteral(), characterLiteral(),
81 cxxBoolLiteral(), stringLiteral(), cxxNullPtrLiteralExpr()));
82 // Include dependent and substituted operands so templates and their
83 // instantiations protect the same outer pair of parentheses.
84 const auto DecltypeOperand =
85 expr(anyOf(declRefExpr(), memberExpr(), dependentScopeDeclRefExpr(),
86 cxxDependentScopeMemberExpr(), unresolvedLookupExpr(),
87 substNonTypeTemplateParmExpr()));
88 const auto DecltypeAutoType = ignoringParens(autoType(isDecltypeAuto()));
89 const auto DecltypeAutoVar = varDecl(hasType(DecltypeAutoType));
90 // Operands that create temporaries are wrapped in ExprWithCleanups.
91 const auto InDecltypeAutoContext = anyOf(
92 hasParent(DecltypeAutoVar),
93 hasParent(
94 expr(anyOf(initListExpr(), parenListExpr()),
95 anyOf(hasParent(DecltypeAutoVar),
96 hasParent(exprWithCleanups(hasParent(DecltypeAutoVar)))))),
97 hasParent(
98 returnStmt(forCallable(functionDecl(returns(DecltypeAutoType))))));
99 const auto IsDecltypeOperand = allOf(
100 subExpr(ignoringParens(DecltypeOperand)),
101 anyOf(hasParent(typeLoc(loc(decltypeType()))), InDecltypeAutoContext,
102 hasParent(exprWithCleanups(InDecltypeAutoContext))));
103 Finder->addMatcher(
104 parenExpr(subExpr(anyOf(
105 parenExpr(), ConstantExpr,
106 declRefExpr(to(namedDecl(unless(
107 matchers::matchesAnyListedRegexName(AllowedDecls))))),
108 memberExpr(),
109 callExpr(unless(cxxOperatorCallExpr(
110 unless(hasAnyOperatorName("()", "[]"))))),
111 arraySubscriptExpr())),
112 isWritten(),
113 unless(anyOf(isInMacro(),
114 // sizeof(...) is common used.
115 hasParent(unaryExprOrTypeTraitExpr()),
116 // typeof(...) parentheses are required syntax.
117 hasParent(typeLoc(isTypeOfExprTypeLoc())),
118 // decltype((x)) differs from decltype(x).
119 IsDecltypeOperand)))
120 .bind("dup"),
121 this);
122}
123
124void RedundantParenthesesCheck::check(const MatchFinder::MatchResult &Result) {
125 const auto *PE = Result.Nodes.getNodeAs<ParenExpr>("dup");
126 diag(PE->getBeginLoc(), "redundant parentheses around expression")
127 << createSpacedRemoval(PE->getLParen(), *Result.SourceManager,
128 getLangOpts())
129 << FixItHint::CreateRemoval(PE->getRParen());
130}
131
132} // namespace clang::tidy::readability
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
RedundantParenthesesCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedRegexName(llvm::ArrayRef< StringRef > NameList)
static FixItHint createSpacedRemoval(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap