================ @@ -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) { ---------------- denzor200 wrote:
We can't move this compound assignment check outside the `isBooleanBitwise` function because it would no longer be evaluated during the recursive traversal of nested binary operations, potentially missing cases where compound assignments with boolean operands appear deeper in the expression tree, like this for example: ``` value |= (flags << 1) | (flags << 2); ``` https://github.com/llvm/llvm-project/pull/167552 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
