[clang-tools-extra] Add clang-tidy check readability-math-missing-parentheses (PR #84481)
Bhuminjay Soni via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 15 03:26:50 PDT 2024
https://github.com/11happy updated https://github.com/llvm/llvm-project/pull/84481
>From 8fdf6306085ed4cf0f77b7e718e374e9f65fedf9 Mon Sep 17 00:00:00 2001
From: 11happy <soni5happy at gmail.com>
Date: Fri, 8 Mar 2024 19:02:47 +0530
Subject: [PATCH 1/4] add clang-tidy check readability-math-missing-parentheses
Signed-off-by: 11happy <soni5happy at gmail.com>
---
.../clang-tidy/readability/CMakeLists.txt | 1 +
.../MathMissingParenthesesCheck.cpp | 167 ++++++++++++++++++
.../readability/MathMissingParenthesesCheck.h | 31 ++++
.../readability/ReadabilityTidyModule.cpp | 3 +
clang-tools-extra/docs/ReleaseNotes.rst | 6 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../readability/math-missing-parentheses.rst | 19 ++
.../readability/math-missing-parentheses.cpp | 42 +++++
8 files changed, 270 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index a6c8cbd8eb448a..0d4fa095501dfb 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangTidyReadabilityModule
IsolateDeclarationCheck.cpp
MagicNumbersCheck.cpp
MakeMemberFunctionConstCheck.cpp
+ MathMissingParenthesesCheck.cpp
MisleadingIndentationCheck.cpp
MisplacedArrayIndexCheck.cpp
NamedParameterCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
new file mode 100644
index 00000000000000..d9574a9fb7a476
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
@@ -0,0 +1,167 @@
+//===--- MathMissingParenthesesCheck.cpp - clang-tidy ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MathMissingParenthesesCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include <set>
+#include <stack>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+void MathMissingParenthesesCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(binaryOperator(unless(hasParent(binaryOperator())),
+ hasDescendant(binaryOperator()))
+ .bind("binOp"),
+ this);
+}
+static int precedenceCheck(const char op) {
+ if (op == '/' || op == '*' || op == '%')
+ return 5;
+
+ else if (op == '+' || op == '-')
+ return 4;
+
+ else if (op == '&')
+ return 3;
+ else if (op == '^')
+ return 2;
+
+ else if (op == '|')
+ return 1;
+
+ else
+ return 0;
+}
+static bool isOperand(const char c) {
+ if (c >= 'a' && c <= 'z')
+ return true;
+ else if (c >= 'A' && c <= 'Z')
+ return true;
+ else if (c >= '0' && c <= '9')
+ return true;
+ else if (c == '$')
+ return true;
+ else
+ return false;
+}
+static bool conditionForNegative(const std::string s, int i,
+ const std::string CurStr) {
+ if (CurStr[0] == '-') {
+ if (i == 0) {
+ return true;
+ } else {
+ while (s[i - 1] == ' ') {
+ i--;
+ }
+ if (!isOperand(s[i - 1])) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+}
+static std::string getOperationOrder(std::string s, std::set<char> &Operators) {
+ std::stack<std::string> StackOne;
+ std::string TempStr = "";
+ for (int i = 0; i < s.length(); i++) {
+ std::string CurStr = "";
+ CurStr += s[i];
+ if (CurStr == " ")
+ continue;
+ else {
+ if (isOperand(CurStr[0]) || conditionForNegative(s, i, CurStr)) {
+ while (i < s.length() && (isOperand(s[i]) || s[i] == '-')) {
+ if (s[i] == '-') {
+ TempStr += "$";
+ } else {
+ TempStr += CurStr;
+ }
+ i++;
+ CurStr = s[i];
+ }
+ TempStr += " ";
+ } else if (CurStr == "(") {
+ StackOne.push("(");
+ } else if (CurStr == ")") {
+ while (StackOne.top() != "(") {
+ TempStr += StackOne.top();
+ StackOne.pop();
+ }
+ StackOne.pop();
+ } else {
+ while (!StackOne.empty() && precedenceCheck(CurStr[0]) <=
+ precedenceCheck((StackOne.top())[0])) {
+ TempStr += StackOne.top();
+ StackOne.pop();
+ }
+ StackOne.push(CurStr);
+ }
+ }
+ }
+ while (!StackOne.empty()) {
+ TempStr += StackOne.top();
+ StackOne.pop();
+ }
+ std::stack<std::string> StackTwo;
+ for (int i = 0; i < TempStr.length(); i++) {
+ if (TempStr[i] == ' ')
+ continue;
+ else if (isOperand(TempStr[i])) {
+ std::string CurStr = "";
+ while (i < TempStr.length() && isOperand(TempStr[i])) {
+ if (TempStr[i] == '$') {
+ CurStr += "-";
+ } else {
+ CurStr += TempStr[i];
+ }
+ i++;
+ }
+ StackTwo.push(CurStr);
+ } else {
+ std::string OperandOne = StackTwo.top();
+ StackTwo.pop();
+ std::string OperandTwo = StackTwo.top();
+ StackTwo.pop();
+ Operators.insert(TempStr[i]);
+ StackTwo.push("(" + OperandTwo + " " + TempStr[i] + " " + OperandOne +
+ ")");
+ }
+ }
+ return StackTwo.top();
+}
+void MathMissingParenthesesCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binOp");
+ if (!BinOp)
+ return;
+ clang::SourceManager &SM = *Result.SourceManager;
+ clang::LangOptions LO = Result.Context->getLangOpts();
+ clang::CharSourceRange Range =
+ clang::CharSourceRange::getTokenRange(BinOp->getSourceRange());
+ std::string Expression = clang::Lexer::getSourceText(Range, SM, LO).str();
+ std::set<char> Operators;
+ std::string FinalExpression = getOperationOrder(Expression, Operators);
+ if (Operators.size() > 1) {
+ if (FinalExpression.length() > 2) {
+ FinalExpression = FinalExpression.substr(1, FinalExpression.length() - 2);
+ }
+ diag(BinOp->getBeginLoc(),
+ "add parantheses to clarify the precedence of operations")
+ << FixItHint::CreateReplacement(Range, FinalExpression);
+ }
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h
new file mode 100644
index 00000000000000..60b402831b45e0
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.h
@@ -0,0 +1,31 @@
+//===--- MathMissingParenthesesCheck.h - clang-tidy -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Checks for mathematical expressions that involve operators of different
+/// priorities.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/math-missing-parentheses.html
+class MathMissingParenthesesCheck : public ClangTidyCheck {
+public:
+ MathMissingParenthesesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MATHMISSINGPARENTHESESCHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 87b299bf1ef1c5..b198153d27ee49 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -31,6 +31,7 @@
#include "IsolateDeclarationCheck.h"
#include "MagicNumbersCheck.h"
#include "MakeMemberFunctionConstCheck.h"
+#include "MathMissingParenthesesCheck.h"
#include "MisleadingIndentationCheck.h"
#include "MisplacedArrayIndexCheck.h"
#include "NamedParameterCheck.h"
@@ -101,6 +102,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-identifier-naming");
CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-conversion");
+ CheckFactories.registerCheck<MathMissingParenthesesCheck>(
+ "readability-math-missing-parentheses");
CheckFactories.registerCheck<RedundantInlineSpecifierCheck>(
"readability-redundant-inline-specifier");
CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index fd2cba4e4f463b..61b9665ffe73ed 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -100,6 +100,12 @@ Improvements to clang-tidy
New checks
^^^^^^^^^^
+- New :doc:`readability-math-missing-parentheses
+ <clang-tidy/checks/readability/math-missing-parentheses>` check.
+
+ Checks for mathematical expressions that involve operators
+ of different priorities.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index f773e80b562e4f..0cc5c217899d4d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -359,6 +359,7 @@ Clang-Tidy Checks
:doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
:doc:`readability-magic-numbers <readability/magic-numbers>`,
:doc:`readability-make-member-function-const <readability/make-member-function-const>`, "Yes"
+ :doc:`readability-math-missing-parentheses <readability/math-missing-parentheses>`, "Yes"
:doc:`readability-misleading-indentation <readability/misleading-indentation>`,
:doc:`readability-misplaced-array-index <readability/misplaced-array-index>`, "Yes"
:doc:`readability-named-parameter <readability/named-parameter>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst
new file mode 100644
index 00000000000000..fb3167e8e0f8f1
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - readability-math-missing-parentheses
+
+readability-math-missing-parentheses
+====================================
+
+Checks for mathematical expressions that involve operators of different priorities.
+
+Before:
+
+.. code-block:: c++
+
+ int x = 1 + 2 * 3 - 4 / 5;
+
+
+After:
+
+.. code-block:: c++
+
+ int x = (1 + (2 * 3)) - (4 / 5);
\ No newline at end of file
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
new file mode 100644
index 00000000000000..54cc0d4dabbdee
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s readability-math-missing-parentheses %t
+
+// FIXME: Add something that triggers the check here.
+void f(){
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ //CHECK-FIXES: int a = 1 + (2 * 3);
+ int a = 1 + 2 * 3;
+
+ int b = 1 + 2 + 3; // No warning
+
+ int c = 1 * 2 * 3; // No warning
+
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ //CHECK-FIXES: int d = (1 + (2 * 3)) - (4 / 5);
+ int d = 1 + 2 * 3 - 4 / 5;
+
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ //CHECK-FIXES: int e = (1 & (2 + 3)) | (4 * 5);
+ int e = 1 & 2 + 3 | 4 * 5;
+
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ //CHECK-FIXES: int f = (1 * -2) + 4;
+ int f = 1 * -2 + 4;
+
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ //CHECK-FIXES: int g = (((1 * 2) * 3) + 4) + 5;
+ int g = 1 * 2 * 3 + 4 + 5;
+
+ // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ // CHECK-FIXES: int h = (120 & (2 + 3)) | (22 * 5);
+ int h = 120 & 2 + 3 | 22 * 5;
+
+ int i = 1 & 2 & 3; // No warning
+
+ int j = 1 | 2 | 3; // No warning
+
+ int k = 1 ^ 2 ^ 3; // No warning
+
+ // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ // CHECK-FIXES: int l = (1 + 2) ^ 3;
+ int l = 1 + 2 ^ 3;
+}
>From dcf739e077a393e71478a4ebe03eddb2a5f32f3c Mon Sep 17 00:00:00 2001
From: 11happy <soni5happy at gmail.com>
Date: Mon, 11 Mar 2024 16:12:14 +0530
Subject: [PATCH 2/4] use ast,remove manual parsing
Signed-off-by: 11happy <soni5happy at gmail.com>
---
.../MathMissingParenthesesCheck.cpp | 159 ++++--------------
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
.../readability/math-missing-parentheses.cpp | 48 +++++-
3 files changed, 71 insertions(+), 138 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
index d9574a9fb7a476..a3fad0a39bfbd5 100644
--- a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
@@ -11,8 +11,9 @@
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Preprocessor.h"
-#include <set>
-#include <stack>
+#include "clang/Rewrite/Core/Rewriter.h"
+#include <iostream>
+using namespace std;
using namespace clang::ast_matchers;
@@ -24,124 +25,25 @@ void MathMissingParenthesesCheck::registerMatchers(MatchFinder *Finder) {
.bind("binOp"),
this);
}
-static int precedenceCheck(const char op) {
- if (op == '/' || op == '*' || op == '%')
- return 5;
- else if (op == '+' || op == '-')
- return 4;
-
- else if (op == '&')
- return 3;
- else if (op == '^')
- return 2;
-
- else if (op == '|')
- return 1;
-
- else
- return 0;
-}
-static bool isOperand(const char c) {
- if (c >= 'a' && c <= 'z')
- return true;
- else if (c >= 'A' && c <= 'Z')
- return true;
- else if (c >= '0' && c <= '9')
- return true;
- else if (c == '$')
- return true;
- else
- return false;
-}
-static bool conditionForNegative(const std::string s, int i,
- const std::string CurStr) {
- if (CurStr[0] == '-') {
- if (i == 0) {
- return true;
- } else {
- while (s[i - 1] == ' ') {
- i--;
- }
- if (!isOperand(s[i - 1])) {
- return true;
- } else {
- return false;
- }
- }
- } else {
- return false;
- }
-}
-static std::string getOperationOrder(std::string s, std::set<char> &Operators) {
- std::stack<std::string> StackOne;
- std::string TempStr = "";
- for (int i = 0; i < s.length(); i++) {
- std::string CurStr = "";
- CurStr += s[i];
- if (CurStr == " ")
- continue;
- else {
- if (isOperand(CurStr[0]) || conditionForNegative(s, i, CurStr)) {
- while (i < s.length() && (isOperand(s[i]) || s[i] == '-')) {
- if (s[i] == '-') {
- TempStr += "$";
- } else {
- TempStr += CurStr;
- }
- i++;
- CurStr = s[i];
- }
- TempStr += " ";
- } else if (CurStr == "(") {
- StackOne.push("(");
- } else if (CurStr == ")") {
- while (StackOne.top() != "(") {
- TempStr += StackOne.top();
- StackOne.pop();
- }
- StackOne.pop();
- } else {
- while (!StackOne.empty() && precedenceCheck(CurStr[0]) <=
- precedenceCheck((StackOne.top())[0])) {
- TempStr += StackOne.top();
- StackOne.pop();
- }
- StackOne.push(CurStr);
- }
- }
- }
- while (!StackOne.empty()) {
- TempStr += StackOne.top();
- StackOne.pop();
- }
- std::stack<std::string> StackTwo;
- for (int i = 0; i < TempStr.length(); i++) {
- if (TempStr[i] == ' ')
- continue;
- else if (isOperand(TempStr[i])) {
- std::string CurStr = "";
- while (i < TempStr.length() && isOperand(TempStr[i])) {
- if (TempStr[i] == '$') {
- CurStr += "-";
- } else {
- CurStr += TempStr[i];
- }
- i++;
- }
- StackTwo.push(CurStr);
- } else {
- std::string OperandOne = StackTwo.top();
- StackTwo.pop();
- std::string OperandTwo = StackTwo.top();
- StackTwo.pop();
- Operators.insert(TempStr[i]);
- StackTwo.push("(" + OperandTwo + " " + TempStr[i] + " " + OperandOne +
- ")");
- }
+void addParantheses(const BinaryOperator *BinOp, clang::Rewriter &Rewrite,
+ const BinaryOperator *ParentBinOp, bool &NeedToDiagnose) {
+ if (!BinOp)
+ return;
+ if (ParentBinOp != nullptr &&
+ ParentBinOp->getOpcode() != BinOp->getOpcode()) {
+ NeedToDiagnose = true;
}
- return StackTwo.top();
+ clang::SourceLocation StartLoc = BinOp->getLHS()->getBeginLoc();
+ clang::SourceLocation EndLoc = BinOp->getRHS()->getEndLoc();
+ Rewrite.InsertText(StartLoc, "(");
+ Rewrite.InsertTextAfterToken(EndLoc, ")");
+ addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()), Rewrite, BinOp,
+ NeedToDiagnose);
+ addParantheses(dyn_cast<BinaryOperator>(BinOp->getRHS()), Rewrite, BinOp,
+ NeedToDiagnose);
}
+
void MathMissingParenthesesCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binOp");
@@ -149,18 +51,17 @@ void MathMissingParenthesesCheck::check(
return;
clang::SourceManager &SM = *Result.SourceManager;
clang::LangOptions LO = Result.Context->getLangOpts();
- clang::CharSourceRange Range =
- clang::CharSourceRange::getTokenRange(BinOp->getSourceRange());
- std::string Expression = clang::Lexer::getSourceText(Range, SM, LO).str();
- std::set<char> Operators;
- std::string FinalExpression = getOperationOrder(Expression, Operators);
- if (Operators.size() > 1) {
- if (FinalExpression.length() > 2) {
- FinalExpression = FinalExpression.substr(1, FinalExpression.length() - 2);
- }
- diag(BinOp->getBeginLoc(),
- "add parantheses to clarify the precedence of operations")
- << FixItHint::CreateReplacement(Range, FinalExpression);
+ Rewriter Rewrite(SM, LO);
+ bool NeedToDiagnose = false;
+ addParantheses(BinOp, Rewrite, nullptr, NeedToDiagnose);
+ clang::SourceLocation StartLoc = BinOp->getLHS()->getBeginLoc();
+ clang::SourceLocation EndLoc =
+ BinOp->getRHS()->getEndLoc().getLocWithOffset(1);
+ clang::SourceRange range(StartLoc, EndLoc);
+ std::string NewExpression = Rewrite.getRewrittenText(range);
+ if (NeedToDiagnose) {
+ diag(StartLoc, "add parantheses to clarify the precedence of operations")
+ << FixItHint::CreateReplacement(range, NewExpression);
}
}
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 61b9665ffe73ed..85fea576187f70 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -103,7 +103,7 @@ New checks
- New :doc:`readability-math-missing-parentheses
<clang-tidy/checks/readability/math-missing-parentheses>` check.
- Checks for mathematical expressions that involve operators
+ Check for mising parantheses in mathematical expressions that involve operators
of different priorities.
New check aliases
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
index 54cc0d4dabbdee..ba936479b666c0 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
@@ -1,9 +1,28 @@
// RUN: %check_clang_tidy %s readability-math-missing-parentheses %t
// FIXME: Add something that triggers the check here.
+
+int foo(){
+ return 5;
+}
+
+int bar(){
+ return 4;
+}
+
+class fun{
+public:
+ int A;
+ double B;
+ fun(){
+ A = 5;
+ B = 5.4;
+ }
+};
+
void f(){
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int a = 1 + (2 * 3);
+ //CHECK-FIXES: int a = (1 + (2 * 3));
int a = 1 + 2 * 3;
int b = 1 + 2 + 3; // No warning
@@ -11,23 +30,23 @@ void f(){
int c = 1 * 2 * 3; // No warning
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int d = (1 + (2 * 3)) - (4 / 5);
+ //CHECK-FIXES: int d = ((1 + (2 * 3)) - (4 / 5));
int d = 1 + 2 * 3 - 4 / 5;
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int e = (1 & (2 + 3)) | (4 * 5);
+ //CHECK-FIXES: int e = ((1 & (2 + 3)) | (4 * 5));
int e = 1 & 2 + 3 | 4 * 5;
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int f = (1 * -2) + 4;
+ //CHECK-FIXES: int f = ((1 * -2) + 4);
int f = 1 * -2 + 4;
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int g = (((1 * 2) * 3) + 4) + 5;
+ //CHECK-FIXES: int g = ((((1 * 2) * 3) + 4) + 5);
int g = 1 * 2 * 3 + 4 + 5;
// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- // CHECK-FIXES: int h = (120 & (2 + 3)) | (22 * 5);
+ // CHECK-FIXES: int h = ((120 & (2 + 3)) | (22 * 5));
int h = 120 & 2 + 3 | 22 * 5;
int i = 1 & 2 & 3; // No warning
@@ -37,6 +56,19 @@ void f(){
int k = 1 ^ 2 ^ 3; // No warning
// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- // CHECK-FIXES: int l = (1 + 2) ^ 3;
+ // CHECK-FIXES: int l = ((1 + 2) ^ 3);
int l = 1 + 2 ^ 3;
-}
+
+ // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ // CHECK-FIXES: int m = ((2 * foo()) + bar());
+ int m = 2 * foo() + bar();
+
+ // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ // CHECK-FIXES: int n = ((1.05 * foo()) + double(bar()));
+ int n = 1.05 * foo() + double(bar());
+
+ // CHECK-MESSAGES: :[[@LINE+3]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ // CHECK-FIXES: int o = (1 + (obj.A * 3)) + obj.B;
+ fun obj;
+ int o = 1 + obj.A * 3 + obj.B;
+}
\ No newline at end of file
>From de33e97d21ad1d7298b4f34a7659b0a569ce9799 Mon Sep 17 00:00:00 2001
From: 11happy <soni5happy at gmail.com>
Date: Fri, 15 Mar 2024 15:55:27 +0530
Subject: [PATCH 3/4] add ignoreimpcasts, use const variables, use
createinsertion instead of createreplacement
Signed-off-by: 11happy <soni5happy at gmail.com>
---
.../MathMissingParenthesesCheck.cpp | 55 ++++++++++---------
.../readability/math-missing-parentheses.rst | 3 +-
.../readability/math-missing-parentheses.cpp | 26 +++++----
3 files changed, 44 insertions(+), 40 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
index a3fad0a39bfbd5..ca1c6581fc60ee 100644
--- a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
@@ -7,13 +7,9 @@
//===----------------------------------------------------------------------===//
#include "MathMissingParenthesesCheck.h"
-#include "../utils/ASTUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include <iostream>
-using namespace std;
using namespace clang::ast_matchers;
@@ -26,42 +22,47 @@ void MathMissingParenthesesCheck::registerMatchers(MatchFinder *Finder) {
this);
}
-void addParantheses(const BinaryOperator *BinOp, clang::Rewriter &Rewrite,
- const BinaryOperator *ParentBinOp, bool &NeedToDiagnose) {
+void addParantheses(
+ const BinaryOperator *BinOp, const BinaryOperator *ParentBinOp,
+ bool &NeedToDiagnose,
+ std::vector<std::pair<clang::SourceLocation, clang::SourceLocation>>
+ &Insertions) {
if (!BinOp)
return;
+
if (ParentBinOp != nullptr &&
ParentBinOp->getOpcode() != BinOp->getOpcode()) {
NeedToDiagnose = true;
}
- clang::SourceLocation StartLoc = BinOp->getLHS()->getBeginLoc();
- clang::SourceLocation EndLoc = BinOp->getRHS()->getEndLoc();
- Rewrite.InsertText(StartLoc, "(");
- Rewrite.InsertTextAfterToken(EndLoc, ")");
- addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()), Rewrite, BinOp,
- NeedToDiagnose);
- addParantheses(dyn_cast<BinaryOperator>(BinOp->getRHS()), Rewrite, BinOp,
- NeedToDiagnose);
+ clang::SourceLocation StartLoc = BinOp->getBeginLoc();
+ clang::SourceLocation EndLoc = BinOp->getEndLoc().getLocWithOffset(1);
+ Insertions.push_back({StartLoc, EndLoc});
+ addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()->IgnoreImpCasts()),
+ BinOp, NeedToDiagnose, Insertions);
+ addParantheses(dyn_cast<BinaryOperator>(BinOp->getRHS()->IgnoreImpCasts()),
+ BinOp, NeedToDiagnose, Insertions);
}
void MathMissingParenthesesCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binOp");
- if (!BinOp)
- return;
- clang::SourceManager &SM = *Result.SourceManager;
- clang::LangOptions LO = Result.Context->getLangOpts();
- Rewriter Rewrite(SM, LO);
bool NeedToDiagnose = false;
- addParantheses(BinOp, Rewrite, nullptr, NeedToDiagnose);
- clang::SourceLocation StartLoc = BinOp->getLHS()->getBeginLoc();
- clang::SourceLocation EndLoc =
- BinOp->getRHS()->getEndLoc().getLocWithOffset(1);
- clang::SourceRange range(StartLoc, EndLoc);
- std::string NewExpression = Rewrite.getRewrittenText(range);
+ std::vector<std::pair<clang::SourceLocation, clang::SourceLocation>>
+ Insertions;
+ addParantheses(BinOp, nullptr, NeedToDiagnose, Insertions);
+ const clang::SourceLocation StartLoc = BinOp->getBeginLoc();
+ const clang::SourceLocation EndLoc = BinOp->getEndLoc().getLocWithOffset(1);
+ const clang::SourceRange range(StartLoc, EndLoc);
+ if (!Insertions.empty()) {
+ Insertions.erase(Insertions.begin());
+ }
if (NeedToDiagnose) {
- diag(StartLoc, "add parantheses to clarify the precedence of operations")
- << FixItHint::CreateReplacement(range, NewExpression);
+ auto const &Diag = diag(
+ StartLoc, "add parantheses to clarify the precedence of operations");
+ for (const auto &Insertion : Insertions) {
+ Diag << FixItHint::CreateInsertion(Insertion.first, "(");
+ Diag << FixItHint::CreateInsertion(Insertion.second, ")");
+ }
}
}
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst
index fb3167e8e0f8f1..72bfdfb9e7242a 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/math-missing-parentheses.rst
@@ -3,7 +3,8 @@
readability-math-missing-parentheses
====================================
-Checks for mathematical expressions that involve operators of different priorities.
+Check for mising parantheses in mathematical expressions that involve operators
+of different priorities.
Before:
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
index ba936479b666c0..a44d08f7b22c1d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/math-missing-parentheses.cpp
@@ -1,7 +1,5 @@
// RUN: %check_clang_tidy %s readability-math-missing-parentheses %t
-// FIXME: Add something that triggers the check here.
-
int foo(){
return 5;
}
@@ -22,7 +20,7 @@ class fun{
void f(){
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int a = (1 + (2 * 3));
+ //CHECK-FIXES: int a = 1 + (2 * 3);
int a = 1 + 2 * 3;
int b = 1 + 2 + 3; // No warning
@@ -30,23 +28,23 @@ void f(){
int c = 1 * 2 * 3; // No warning
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int d = ((1 + (2 * 3)) - (4 / 5));
+ //CHECK-FIXES: int d = (1 + (2 * 3)) - (4 / 5);
int d = 1 + 2 * 3 - 4 / 5;
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int e = ((1 & (2 + 3)) | (4 * 5));
+ //CHECK-FIXES: int e = (1 & (2 + 3)) | (4 * 5);
int e = 1 & 2 + 3 | 4 * 5;
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int f = ((1 * -2) + 4);
+ //CHECK-FIXES: int f = (1 * -2) + 4;
int f = 1 * -2 + 4;
//CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- //CHECK-FIXES: int g = ((((1 * 2) * 3) + 4) + 5);
+ //CHECK-FIXES: int g = (((1 * 2) * 3) + 4) + 5;
int g = 1 * 2 * 3 + 4 + 5;
// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- // CHECK-FIXES: int h = ((120 & (2 + 3)) | (22 * 5));
+ // CHECK-FIXES: int h = (120 & (2 + 3)) | (22 * 5);
int h = 120 & 2 + 3 | 22 * 5;
int i = 1 & 2 & 3; // No warning
@@ -56,19 +54,23 @@ void f(){
int k = 1 ^ 2 ^ 3; // No warning
// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- // CHECK-FIXES: int l = ((1 + 2) ^ 3);
+ // CHECK-FIXES: int l = (1 + 2) ^ 3;
int l = 1 + 2 ^ 3;
// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- // CHECK-FIXES: int m = ((2 * foo()) + bar());
+ // CHECK-FIXES: int m = (2 * foo()) + bar();
int m = 2 * foo() + bar();
// CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
- // CHECK-FIXES: int n = ((1.05 * foo()) + double(bar()));
+ // CHECK-FIXES: int n = (1.05 * foo()) + double(bar());
int n = 1.05 * foo() + double(bar());
// CHECK-MESSAGES: :[[@LINE+3]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
// CHECK-FIXES: int o = (1 + (obj.A * 3)) + obj.B;
fun obj;
int o = 1 + obj.A * 3 + obj.B;
-}
\ No newline at end of file
+
+ // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: add parantheses to clarify the precedence of operations [readability-math-missing-parentheses]
+ // CHECK-FIXES: int p = 1U + (2 * 3);
+ int p = 1U + 2 * 3;
+}
>From fa95ab7ad216b6498b579db55ff1594da3fe0aab Mon Sep 17 00:00:00 2001
From: 11happy <soni5happy at gmail.com>
Date: Fri, 15 Mar 2024 15:56:36 +0530
Subject: [PATCH 4/4] remove unnecessary header
Signed-off-by: 11happy <soni5happy at gmail.com>
---
.../clang-tidy/readability/MathMissingParenthesesCheck.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
index ca1c6581fc60ee..ad1d0744f660b3 100644
--- a/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MathMissingParenthesesCheck.cpp
@@ -9,7 +9,6 @@
#include "MathMissingParenthesesCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Rewrite/Core/Rewriter.h"
using namespace clang::ast_matchers;
@@ -34,8 +33,8 @@ void addParantheses(
ParentBinOp->getOpcode() != BinOp->getOpcode()) {
NeedToDiagnose = true;
}
- clang::SourceLocation StartLoc = BinOp->getBeginLoc();
- clang::SourceLocation EndLoc = BinOp->getEndLoc().getLocWithOffset(1);
+ const clang::SourceLocation StartLoc = BinOp->getBeginLoc();
+ const clang::SourceLocation EndLoc = BinOp->getEndLoc().getLocWithOffset(1);
Insertions.push_back({StartLoc, EndLoc});
addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()->IgnoreImpCasts()),
BinOp, NeedToDiagnose, Insertions);
More information about the cfe-commits
mailing list