1//===--- MathMissingParenthesesCheck.cpp - clang-tidy ---------------------===//
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
9#include "MathMissingParenthesesCheck.h"
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
16namespace clang::tidy::readability {
17
18void MathMissingParenthesesCheck::registerMatchers(MatchFinder *Finder) {
19 Finder->addMatcher(
20 NodeMatch: binaryOperator(
21 unless(hasParent(binaryOperator(unless(isAssignmentOperator()),
22 unless(isComparisonOperator())))),
23 unless(isAssignmentOperator()), unless(isComparisonOperator()),
24 unless(hasAnyOperatorName("&&", "||")),
25 hasDescendant(binaryOperator()))
26 .bind(ID: "binOp"),
27 Action: 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 addParantheses(const BinaryOperator *BinOp,
52 const BinaryOperator *ParentBinOp,
53 ClangTidyCheck *Check,
54 const clang::SourceManager &SM,
55 const clang::LangOptions &LangOpts) {
56 if (!BinOp)
57 return;
58
59 int Precedence1 = getPrecedence(BinOp);
60 int Precedence2 = getPrecedence(BinOp: ParentBinOp);
61
62 if (ParentBinOp != nullptr && Precedence1 != Precedence2 && Precedence1 > 0 &&
63 Precedence2 > 0) {
64 const clang::SourceLocation StartLoc = BinOp->getBeginLoc();
65 const clang::SourceLocation EndLoc =
66 clang::Lexer::getLocForEndOfToken(Loc: BinOp->getEndLoc(), Offset: 0, SM, LangOpts);
67
68 auto Diag =
69 Check->diag(Loc: StartLoc,
70 Description: "'%0' has higher precedence than '%1'; add parentheses to "
71 "explicitly specify the order of operations")
72 << (Precedence1 > Precedence2 ? BinOp->getOpcodeStr()
73 : ParentBinOp->getOpcodeStr())
74 << (Precedence1 > Precedence2 ? ParentBinOp->getOpcodeStr()
75 : BinOp->getOpcodeStr())
76 << SourceRange(StartLoc, EndLoc);
77
78 if (EndLoc.isValid()) {
79 Diag << FixItHint::CreateInsertion(InsertionLoc: StartLoc, Code: "(")
80 << FixItHint::CreateInsertion(InsertionLoc: EndLoc, Code: ")");
81 }
82 }
83
84 addParantheses(BinOp: dyn_cast<BinaryOperator>(Val: BinOp->getLHS()->IgnoreImpCasts()),
85 ParentBinOp: BinOp, Check, SM, LangOpts);
86 addParantheses(BinOp: dyn_cast<BinaryOperator>(Val: BinOp->getRHS()->IgnoreImpCasts()),
87 ParentBinOp: BinOp, Check, SM, LangOpts);
88}
89
90void MathMissingParenthesesCheck::check(
91 const MatchFinder::MatchResult &Result) {
92 const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>(ID: "binOp");
93 const SourceManager &SM = *Result.SourceManager;
94 const clang::LangOptions &LO = Result.Context->getLangOpts();
95 addParantheses(BinOp, ParentBinOp: nullptr, Check: this, SM, LangOpts: LO);
96}
97
98} // namespace clang::tidy::readability
99

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp