================
@@ -0,0 +1,302 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "BoolBitwiseOperationCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include <array>
+#include <optional>
+#include <utility>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+static const DynTypedNode *ignoreParensTowardsTheRoot(const DynTypedNode *N,
+                                                      ASTContext *AC) {
+  if (const auto *S = N->get<Stmt>()) {
+    if (isa<ParenExpr>(S)) {
+      auto Parents = AC->getParents(*S);
+      // FIXME: do we need to consider all `Parents` ?
+      if (!Parents.empty())
+        return ignoreParensTowardsTheRoot(&Parents[0], AC);
+    }
+  }
+  return N;
+}
+
+static bool assignsToBoolean(const BinaryOperator *BinOp, ASTContext *AC) {
+  TraversalKindScope RAII(*AC, TK_AsIs);
+  auto Parents = AC->getParents(*BinOp);
+
+  return llvm::any_of(Parents, [&](const DynTypedNode &Parent) {
+    const auto *S = ignoreParensTowardsTheRoot(&Parent, AC)->get<Stmt>();
+    const auto *ICE = dyn_cast_if_present<ImplicitCastExpr>(S);
+    return ICE ? ICE->getType().getDesugaredType(*AC)->isBooleanType() : false;
+  });
+}
+
+static constexpr std::array<std::pair<StringRef, StringRef>, 8U>
+    OperatorsTransformation{{{"|", "||"},
+                             {"|=", "||"},
+                             {"&", "&&"},
+                             {"&=", "&&"},
+                             {"bitand", "and"},
+                             {"and_eq", "and"},
+                             {"bitor", "or"},
+                             {"or_eq", "or"}}};
+
+static StringRef translate(StringRef Value) {
+  for (const auto &[Bitwise, Logical] : OperatorsTransformation) {
+    if (Value == Bitwise)
+      return Logical;
+  }
+
+  return {};
+}
+
+static bool isBooleanBitwise(const BinaryOperator *BinOp, ASTContext *AC,
+                             std::optional<bool> &RootAssignsToBoolean) {
+  if (!BinOp)
+    return false;
+
+  for (const auto &[Bitwise, _] : OperatorsTransformation) {
+    if (BinOp->getOpcodeStr() == Bitwise) {
+      bool IsBooleanLHS = BinOp->getLHS()
+                              ->IgnoreImpCasts()
+                              ->getType()
+                              .getDesugaredType(*AC)
+                              ->isBooleanType();
+      bool IsBooleanRHS = BinOp->getRHS()
+                              ->IgnoreImpCasts()
+                              ->getType()
+                              .getDesugaredType(*AC)
+                              ->isBooleanType();
+      if (IsBooleanLHS && IsBooleanRHS) {
+        RootAssignsToBoolean = RootAssignsToBoolean.value_or(false);
+        return true;
+      }
+      if (((IsBooleanLHS || IsBooleanRHS) && assignsToBoolean(BinOp, AC)) ||
+          RootAssignsToBoolean.value_or(false)) {
+        RootAssignsToBoolean = RootAssignsToBoolean.value_or(true);
+        return true;
+      }
+      if (BinOp->isCompoundAssignmentOp() && IsBooleanLHS) {
+        RootAssignsToBoolean = RootAssignsToBoolean.value_or(true);
+        return true;
+      }
+
+      std::optional<bool> DummyFlag = false;
+      IsBooleanLHS =
+          IsBooleanLHS ||
+          isBooleanBitwise(
+              dyn_cast<BinaryOperator>(BinOp->getLHS()->IgnoreParenImpCasts()),
+              AC, DummyFlag);
+      IsBooleanRHS =
+          IsBooleanRHS ||
+          isBooleanBitwise(
+              dyn_cast<BinaryOperator>(BinOp->getRHS()->IgnoreParenImpCasts()),
+              AC, DummyFlag);
+
+      if (IsBooleanLHS && IsBooleanRHS) {
+        RootAssignsToBoolean = RootAssignsToBoolean.value_or(false);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static const Expr *getAcceptableCompoundsLHS(const BinaryOperator *BinOp) {
+  assert(BinOp->isCompoundAssignmentOp());
+
+  if (const auto *DeclRefLHS =
+          dyn_cast<DeclRefExpr>(BinOp->getLHS()->IgnoreImpCasts()))
+    return DeclRefLHS;
+  if (const auto *MemberLHS =
+          dyn_cast<MemberExpr>(BinOp->getLHS()->IgnoreImpCasts()))
+    return MemberLHS;
+
+  return nullptr;
+}
+
+BoolBitwiseOperationCheck::BoolBitwiseOperationCheck(StringRef Name,
+                                                     ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      UnsafeMode(Options.get("UnsafeMode", false)),
+      IgnoreMacros(Options.get("IgnoreMacros", false)) {}
+
+void BoolBitwiseOperationCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "UnsafeMode", UnsafeMode);
+  Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+}
+
+void BoolBitwiseOperationCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      binaryOperator(unless(isExpansionInSystemHeader()),
+                     unless(hasParent(binaryOperator())) // ignoring parenExpr
+                     )
+          .bind("binOpRoot"),
+      this);
----------------
denzor200 wrote:

Now we can't do it because with `TK_IgnoreUnlessSpelledInSource` impossible to 
match `implicitCastExpr`.
Give me some time to figure out how to write it without 
`TK_IgnoreUnlessSpelledInSource`

https://github.com/llvm/llvm-project/pull/167552
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to