clang-tools 23.0.0git
MathMissingParenthesesCheck.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 "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
13
14using namespace clang::ast_matchers;
15
17
19 Finder->addMatcher(
20 binaryOperator(
21 unless(hasParent(binaryOperator(unless(isAssignmentOperator()),
22 unless(isComparisonOperator())))),
23 unless(isAssignmentOperator()), unless(isComparisonOperator()),
24 unless(hasAnyOperatorName("&&", "||")),
25 hasDescendant(binaryOperator()))
26 .bind("binOp"),
27 this);
28}
29
30static int getPrecedence(const BinaryOperator *BinOp) {
31 if (!BinOp)
32 return 0;
33 switch (BinOp->getOpcode()) {
34 case BO_Mul:
35 case BO_Div:
36 case BO_Rem:
37 return 5;
38 case BO_Add:
39 case BO_Sub:
40 return 4;
41 case BO_And:
42 return 3;
43 case BO_Xor:
44 return 2;
45 case BO_Or:
46 return 1;
47 default:
48 return 0;
49 }
50}
51static void addParentheses(const Expr *E, const BinaryOperator *ParentBinOp,
52 ClangTidyCheck *Check, const SourceManager &SM,
53 const LangOptions &LangOpts) {
54 if (const auto *Paren = dyn_cast<ParenExpr>(E)) {
55 addParentheses(Paren->getSubExpr()->IgnoreImpCasts(), nullptr, Check, SM,
56 LangOpts);
57 return;
58 }
59
60 const auto *BinOp = dyn_cast<BinaryOperator>(E);
61 if (!BinOp)
62 return;
63
64 const int Precedence1 = getPrecedence(BinOp);
65 const int Precedence2 = getPrecedence(ParentBinOp);
66
67 if (ParentBinOp != nullptr && Precedence1 != Precedence2 && Precedence1 > 0 &&
68 Precedence2 > 0) {
69 const SourceLocation StartLoc = BinOp->getBeginLoc();
70 const SourceLocation EndLoc =
71 Lexer::getLocForEndOfToken(BinOp->getEndLoc(), 0, SM, LangOpts);
72
73 auto Diag =
74 Check->diag(StartLoc,
75 "'%0' has higher precedence than '%1'; add parentheses to "
76 "explicitly specify the order of operations")
77 << (Precedence1 > Precedence2 ? BinOp->getOpcodeStr()
78 : ParentBinOp->getOpcodeStr())
79 << (Precedence1 > Precedence2 ? ParentBinOp->getOpcodeStr()
80 : BinOp->getOpcodeStr())
81 << SourceRange(StartLoc, EndLoc);
82
83 if (EndLoc.isValid()) {
84 Diag << FixItHint::CreateInsertion(StartLoc, "(")
85 << FixItHint::CreateInsertion(EndLoc, ")");
86 }
87 }
88
89 addParentheses(BinOp->getLHS()->IgnoreImpCasts(), BinOp, Check, SM, LangOpts);
90 addParentheses(BinOp->getRHS()->IgnoreImpCasts(), BinOp, Check, SM, LangOpts);
91}
92
94 const MatchFinder::MatchResult &Result) {
95 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binOp");
96 const SourceManager &SM = *Result.SourceManager;
97 const LangOptions &LO = Result.Context->getLangOpts();
98 addParentheses(BinOp, nullptr, this, SM, LO);
99}
100
101} // namespace clang::tidy::readability
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static void addParentheses(const Expr *E, const BinaryOperator *ParentBinOp, ClangTidyCheck *Check, const SourceManager &SM, const LangOptions &LangOpts)
static int getPrecedence(const BinaryOperator *BinOp)