diff --git a/clang-tools-extra/clang-tidy/misc/BoolBitwiseOperationCheck.cpp b/clang-tools-extra/clang-tidy/misc/BoolBitwiseOperationCheck.cpp new file mode 100644 index 0000000000000..2771f81e97283 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/BoolBitwiseOperationCheck.cpp @@ -0,0 +1,290 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +using namespace clang::ast_matchers; + +namespace clang::tidy::misc { + +static const DynTypedNode *ignoreParensTowardsTheRoot(const DynTypedNode *N, + ASTContext *AC) { + if (const auto *S = N->get(); isa_and_nonnull(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) { + const 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(); + const auto *ICE = dyn_cast_if_present(S); + return ICE ? ICE->getType().getDesugaredType(*AC)->isBooleanType() : false; + }); +} + +static constexpr std::array, 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 &RootAssignsToBoolean) { + if (!BinOp) + return false; + + if (!llvm::is_contained(llvm::make_first_range(OperatorsTransformation), + BinOp->getOpcodeStr())) + return false; + + const auto IsBooleanType = [&AC](const Expr *Expr) -> bool { + return Expr->IgnoreImpCasts() + ->getType() + .getDesugaredType(*AC) + ->isBooleanType(); + }; + + bool IsBooleanLHS = IsBooleanType(BinOp->getLHS()); + bool IsBooleanRHS = IsBooleanType(BinOp->getRHS()); + 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 DummyFlag = false; + IsBooleanLHS = IsBooleanLHS || + isBooleanBitwise(dyn_cast( + BinOp->getLHS()->IgnoreParenImpCasts()), + AC, DummyFlag); + IsBooleanRHS = IsBooleanRHS || + isBooleanBitwise(dyn_cast( + 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()); + const Expr *LHS = BinOp->getLHS()->IgnoreImpCasts(); + return isa(LHS) ? LHS : 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); +} + +void BoolBitwiseOperationCheck::emitWarningAndChangeOperatorsIfPossible( + const BinaryOperator *BinOp, const BinaryOperator *ParentBinOp, + const clang::SourceManager &SM, clang::ASTContext &Ctx) { + auto DiagEmitter = [BinOp, this] { + return diag(BinOp->getOperatorLoc(), + "use logical operator '%0' for boolean semantics instead of " + "bitwise operator '%1'") + << translate(BinOp->getOpcodeStr()) << BinOp->getOpcodeStr(); + }; + + const bool HasVolatileOperand = llvm::any_of( + std::array{BinOp->getLHS(), BinOp->getRHS()}, [&](const Expr *E) { + return E->IgnoreImpCasts() + ->getType() + .getDesugaredType(Ctx) + .isVolatileQualified(); + }); + if (HasVolatileOperand) { + DiagEmitter(); + return; + } + + const bool HasSideEffects = BinOp->getRHS()->HasSideEffects( + Ctx, /*IncludePossibleEffects=*/!UnsafeMode); + if (HasSideEffects) { + DiagEmitter(); + return; + } + + SourceLocation Loc = BinOp->getOperatorLoc(); + + if (Loc.isInvalid() || Loc.isMacroID()) { + IgnoreMacros || DiagEmitter(); + return; + } + + Loc = SM.getSpellingLoc(Loc); + if (Loc.isInvalid() || Loc.isMacroID()) { + IgnoreMacros || DiagEmitter(); + return; + } + + const CharSourceRange TokenRange = CharSourceRange::getTokenRange(Loc); + if (TokenRange.isInvalid()) { + IgnoreMacros || DiagEmitter(); + return; + } + + const StringRef FixSpelling = + translate(Lexer::getSourceText(TokenRange, SM, Ctx.getLangOpts())); + + if (FixSpelling.empty()) { + DiagEmitter(); + return; + } + + FixItHint InsertEqual; + if (BinOp->isCompoundAssignmentOp()) { + const auto *LHS = getAcceptableCompoundsLHS(BinOp); + if (!LHS) { + DiagEmitter(); + return; + } + const SourceLocation LocLHS = LHS->getEndLoc(); + if (LocLHS.isInvalid() || LocLHS.isMacroID()) { + IgnoreMacros || DiagEmitter(); + return; + } + const SourceLocation InsertLoc = + clang::Lexer::getLocForEndOfToken(LocLHS, 0, SM, Ctx.getLangOpts()); + if (InsertLoc.isInvalid() || InsertLoc.isMacroID()) { + IgnoreMacros || DiagEmitter(); + return; + } + auto SourceText = static_cast(Lexer::getSourceText( + CharSourceRange::getTokenRange(LHS->getSourceRange()), SM, + Ctx.getLangOpts())); + llvm::erase_if(SourceText, + [](unsigned char Ch) { return std::isspace(Ch); }); + InsertEqual = FixItHint::CreateInsertion(InsertLoc, " = " + SourceText); + } + + auto ReplaceOperator = FixItHint::CreateReplacement(TokenRange, FixSpelling); + + std::optional ParentOpcode; + if (ParentBinOp) + ParentOpcode = ParentBinOp->getOpcode(); + + const auto *RHS = dyn_cast(BinOp->getRHS()->IgnoreImpCasts()); + std::optional RHSOpcode; + if (RHS) + RHSOpcode = RHS->getOpcode(); + + const Expr *SurroundedExpr = nullptr; + if ((BinOp->getOpcode() == BO_Or && ParentOpcode == BO_LAnd) || + (BinOp->getOpcode() == BO_And && + llvm::is_contained({BO_Xor, BO_Or}, ParentOpcode))) { + const Expr *Side = ParentBinOp->getLHS()->IgnoreParenImpCasts() == BinOp + ? ParentBinOp->getLHS() + : ParentBinOp->getRHS(); + SurroundedExpr = Side->IgnoreImpCasts(); + assert(SurroundedExpr->IgnoreParens() == BinOp); + } else if (BinOp->getOpcode() == BO_AndAssign && RHSOpcode == BO_LOr) + SurroundedExpr = RHS; + + if (isa_and_nonnull(SurroundedExpr)) + SurroundedExpr = nullptr; + + FixItHint InsertBrace1; + FixItHint InsertBrace2; + if (SurroundedExpr) { + const SourceLocation InsertFirstLoc = SurroundedExpr->getBeginLoc(); + const SourceLocation InsertSecondLoc = clang::Lexer::getLocForEndOfToken( + SurroundedExpr->getEndLoc(), 0, SM, Ctx.getLangOpts()); + if (InsertFirstLoc.isInvalid() || InsertFirstLoc.isMacroID() || + InsertSecondLoc.isInvalid() || InsertSecondLoc.isMacroID()) { + IgnoreMacros || DiagEmitter(); + return; + } + InsertBrace1 = FixItHint::CreateInsertion(InsertFirstLoc, "("); + InsertBrace2 = FixItHint::CreateInsertion(InsertSecondLoc, ")"); + } + + DiagEmitter() << InsertEqual << ReplaceOperator << InsertBrace1 + << InsertBrace2; +} + +void BoolBitwiseOperationCheck::visitBinaryTreesNode( + const BinaryOperator *BinOp, const BinaryOperator *ParentBinOp, + const clang::SourceManager &SM, clang::ASTContext &Ctx, + std::optional &RootAssignsToBoolean) { + if (!BinOp) + return; + + if (isBooleanBitwise(BinOp, &Ctx, RootAssignsToBoolean)) + emitWarningAndChangeOperatorsIfPossible(BinOp, ParentBinOp, SM, Ctx); + + visitBinaryTreesNode( + dyn_cast(BinOp->getLHS()->IgnoreParenImpCasts()), BinOp, + SM, Ctx, RootAssignsToBoolean); + visitBinaryTreesNode( + dyn_cast(BinOp->getRHS()->IgnoreParenImpCasts()), BinOp, + SM, Ctx, RootAssignsToBoolean); +} + +void BoolBitwiseOperationCheck::check(const MatchFinder::MatchResult &Result) { + const auto *BinOpRoot = Result.Nodes.getNodeAs("binOpRoot"); + const SourceManager &SM = *Result.SourceManager; + ASTContext &Ctx = *Result.Context; + std::optional RootAssignsToBoolean = std::nullopt; + visitBinaryTreesNode(BinOpRoot, nullptr, SM, Ctx, RootAssignsToBoolean); +} + +} // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/misc/BoolBitwiseOperationCheck.h b/clang-tools-extra/clang-tidy/misc/BoolBitwiseOperationCheck.h new file mode 100644 index 0000000000000..3725e0b54ebc5 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/BoolBitwiseOperationCheck.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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_MISC_BOOLBITWISEOPERATIONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BOOLBITWISEOPERATIONCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::misc { + +/// Finds potentially inefficient use of bitwise operators such as ``&``, ``|`` +/// and their compound analogues on Boolean values where logical operators like +/// ``&&`` and ``||`` would be more appropriate. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/misc/bool-bitwise-operation.html +class BoolBitwiseOperationCheck : public ClangTidyCheck { +public: + BoolBitwiseOperationCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus || LangOpts.C99; + } + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + void emitWarningAndChangeOperatorsIfPossible( + const BinaryOperator *BinOp, const BinaryOperator *ParentBinOp, + const clang::SourceManager &SM, clang::ASTContext &Ctx); + void visitBinaryTreesNode(const BinaryOperator *BinOp, + const BinaryOperator *ParentBinOp, + const clang::SourceManager &SM, + clang::ASTContext &Ctx, + std::optional &RootAssignsToBoolean); + + bool UnsafeMode; + bool IgnoreMacros; +}; + +} // namespace clang::tidy::misc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BOOLBITWISEOPERATIONCHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index 6214ee92927f2..7c494519d84f0 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -18,6 +18,7 @@ add_custom_target(genconfusable DEPENDS Confusables.inc) set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourcegenning") add_clang_library(clangTidyMiscModule STATIC + BoolBitwiseOperationCheck.cpp ConstCorrectnessCheck.cpp CoroutineHostileRAIICheck.cpp DefinitionsInHeadersCheck.cpp diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index 347fa2a82e43c..9312bdef50b9a 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "BoolBitwiseOperationCheck.h" #include "ConfusableIdentifierCheck.h" #include "ConstCorrectnessCheck.h" #include "CoroutineHostileRAIICheck.h" @@ -40,6 +41,8 @@ namespace misc { class MiscModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "misc-bool-bitwise-operation"); CheckFactories.registerCheck( "misc-confusable-identifiers"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 666865cfb2fcd..4f83047e94da7 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -220,6 +220,13 @@ New checks Finds calls to STL library iterator algorithms that could be replaced with LLVM range-based algorithms from ``llvm/ADT/STLExtras.h``. +- New :doc:`misc-bool-bitwise-operation + ` check. + + Finds potentially inefficient use of bitwise operators such as ``&``, ``|`` + and their compound analogues on Boolean values where logical operators like + ``&&`` and ``||`` would be more appropriate. + - New :doc:`misc-override-with-different-visibility ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index e2875604af72b..a1b7ab5eeb90f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -262,6 +262,7 @@ Clang-Tidy Checks :doc:`llvmlibc-implementation-in-namespace `, :doc:`llvmlibc-inline-function-decl `, "Yes" :doc:`llvmlibc-restrict-system-libc-headers `, "Yes" + :doc:`misc-bool-bitwise-operation `, "Yes" :doc:`misc-confusable-identifiers `, :doc:`misc-const-correctness `, "Yes" :doc:`misc-coroutine-hostile-raii `, diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/bool-bitwise-operation.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/bool-bitwise-operation.rst new file mode 100644 index 0000000000000..f7f03575ae126 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/bool-bitwise-operation.rst @@ -0,0 +1,76 @@ +.. title:: clang-tidy - misc-bool-bitwise-operation + +misc-bool-bitwise-operation +=========================== + +Finds potentially inefficient use of bitwise operators such as ``&``, ``|`` +and their compound analogues on Boolean values where logical operators like +``&&`` and ``||`` would be more appropriate. + +Bitwise operations on Booleans can incur unnecessary performance overhead due +to implicit integer conversions and missed short-circuit evaluation. + +.. code-block:: c++ + + bool invalid = false; + invalid |= x > limit.x; // warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' + // 400 | invalid |= x > limit.x; + // | ^~ + // | = invalid || + invalid |= y > limit.y; // warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' + // 401 | invalid |= y > limit.y; + // | ^~ + // | = invalid || + invalid |= z > limit.z; // warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' + // 402 | invalid |= z > limit.z; + // | ^~ + // | = invalid || + if (invalid) { + // error handling + } + +These 3 warnings suggest assigning the result of a logical ``||`` operation +instead of using the ``|=`` operator: + +.. code-block:: c++ + + bool invalid = false; + invalid = invalid || x > limit.x; + invalid = invalid || y > limit.x; + invalid = invalid || z > limit.z; + if (invalid) { + // error handling + } + +It is not always a safe transformation though. The following case will warn +without fix-it to preserve the semantics. + +.. code-block:: c++ + + volatile bool invalid = false; + invalid |= x > limit.x; // warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' + +Limitations +----------- + +* Bitwise operators inside templates aren't guaranteed to match. + +.. code-block:: c++ + + template + void f(X a, X b) { + a | b; // the warning may not be emitted + } + +Options +------- + +.. option:: UnsafeMode + + Provide more fix-it hints even when they might change evaluation order or + skip side effects. Default value is `false`. + +.. option:: IgnoreMacros + + Don't warn if a macro inside the expression body prevents replacing a + bitwise operator with a logical one. Default value is `false`. \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-change-possible-side-effect.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-change-possible-side-effect.cpp new file mode 100644 index 0000000000000..a39131ec54a8e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-change-possible-side-effect.cpp @@ -0,0 +1,82 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t \ +// RUN: -config="{CheckOptions: { \ +// RUN: misc-bool-bitwise-operation.UnsafeMode: true }}" + +bool function_with_possible_side_effects(); + +void bad_possible_side_effects() { + bool a = true, b = false; + + a | function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || function_with_possible_side_effects(); + + a & function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && function_with_possible_side_effects(); + + a |= function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || function_with_possible_side_effects(); + + a &= function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && function_with_possible_side_effects(); + + bool c = true; + + a &= function_with_possible_side_effects() && c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && function_with_possible_side_effects() && c; + + a &= b && function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && b && function_with_possible_side_effects(); + + a |= function_with_possible_side_effects() || c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || function_with_possible_side_effects() || c; + + a |= b || function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || b || function_with_possible_side_effects(); +} + +void bad_definitely_side_effects() { + bool a = true, b = false; + int acc = 0; + + a | (acc++, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a & (acc++, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a |= (acc++, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a &= (acc++, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + bool c = true; + + a &= (acc++, b) && c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a &= b && (acc++, c); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a |= (acc++, b) || c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a |= b || (acc++, c); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-flags.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-flags.cpp new file mode 100644 index 0000000000000..a7b6af0413484 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-flags.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +bool normal() { + unsigned flags = 100; + if (flags & 0xFFFFFFF8) { + + } + return flags & 0x20; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-ignore-macros.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-ignore-macros.cpp new file mode 100644 index 0000000000000..9980e65fddeaa --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-ignore-macros.cpp @@ -0,0 +1,53 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t \ +// RUN: -config="{CheckOptions: { \ +// RUN: misc-bool-bitwise-operation.IgnoreMacros: true }}" + +#define CAT(a, b) a ## b +#define IDENT(a) a + +void bad_in_macro() { + bool a = true, b = false; + + // change operator - BAD + IDENT(a |) b; + a IDENT(& b); + IDENT(a |=) b; + a IDENT(&= b); + + // change operator - GOOD + IDENT(a) | b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a) || b; + a & IDENT(b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && IDENT(b); + IDENT(a) & IDENT(b); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a) && IDENT(b); + + // insert `)` - BAD + bool c = true, e = false; + a && b | IDENT(c &&) e; + + // insert `)` - GOOD + a && b | c IDENT(&& e); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && (b || c) IDENT(&& e); + + // insert `(` - BAD + a IDENT(&& b) | c && e; + + // insert `(` - GOOD + IDENT(a &&) b | c && e; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a &&) (b || c) && e; + + bool ab = false; + // insert ` = a` - BAD + CAT(a, b) &= b; + + // insert ` = a`- GOOD + b &= CAT(a, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = b && CAT(a, b); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-nontraditional.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-nontraditional.cpp new file mode 100644 index 0000000000000..c6a8a7810c93b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-nontraditional.cpp @@ -0,0 +1,411 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +bool& normal() { + int a = 100, b = 200; + + a bitor b; + a bitand b; + a or_eq b; + a and_eq b; + + static bool st = false; + return st; +} + +bool bad() noexcept __attribute__((pure)) { + bool a = true, b = false; + a bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or b; + a bitand b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and b; + a or_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a or b; + a and_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a and b; + + return true; +} + +bool global_1 = bad() bitor bad(); +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] +// CHECK-FIXES: bool global_1 = bad() or bad(); +bool global_2 = bad() bitand bad(); +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] +// CHECK-FIXES: bool global_2 = bad() and bad(); + +using Boolean = bool; + +bool bad_typedef() { + Boolean a = true, b = false; + a bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or b; + a bitand b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and b; + a or_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a or b; + a and_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a and b; + return true; +} + +bool function_with_possible_side_effects(); + +void bad_side_effects() { + bool a = true, b = false; + + a bitor function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a bitand function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + function_with_possible_side_effects() bitor a; + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() or a; + + function_with_possible_side_effects() bitand a; + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() and a; + a or_eq function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a and_eq function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // count of evaluation with side effect remains the same, so the fixit will be provided + bool c = true; + + a or function_with_possible_side_effects() bitor c; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or function_with_possible_side_effects() or c; + + function_with_possible_side_effects() or b bitor c; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() or b or c; + + a and function_with_possible_side_effects() bitand c; + // CHECK-MESSAGES: :[[@LINE-1]]:49: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and function_with_possible_side_effects() and c; + + function_with_possible_side_effects() and b bitand c; + // CHECK-MESSAGES: :[[@LINE-1]]:49: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() and b and c; + + // but here the count of evaluation migh be changed - no fix must be provided + + a and_eq function_with_possible_side_effects() and c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a and_eq b and function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a or_eq function_with_possible_side_effects() or c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a or_eq b or function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} + +void bad_side_effects_volatile() { + bool a = true; + volatile bool b = false; + bool c = true; + + a bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a bitand b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a or_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a and_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + (a bitor c) bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (a or c) bitor b; + + a bitor c bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or c bitor b; +} + +void bad_with_priors() { + bool a = false, b = true, c = true; + a and b bitor c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and (b or c); + a and b bitand c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and b and c; + a or b bitand c; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or b and c; + a or b bitor c; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or b or c; + b bitor c and a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b or c) and a; + + bool q = (true and false bitor true) and (false bitor true and (false and true bitor false)); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:53: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:84: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool q = (true and (false or true)) and ((false or true) and (false and (true or false))); +} + +void bad_with_priors2() { + bool a = false, b = true, c = true; + bool r; + a xor b bitand c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a xor (b and c); + + // braces added in the first change + a bitor b bitand c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or (b and c); + + b bitand c xor a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b and c) xor a; + + // braces added in the first change + b bitand c bitor a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b and c) or a; +} + +template +T ident(T val) { return val; } + +// cases to check `hasAncestor` works as we expected: +void bad_has_ancestor() { + bool a = false, b = true, c = true; + bool d = false; + d xor (a and b bitand c); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: d xor (a and b and c); + + a xor ident(b bitand c or a); + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a xor ident(b and c or a); + + a bitor ident(a ? b bitand c : c); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a bitor ident(a ? b and c : c); +} + +void bad_with_priors_already_braced() { + bool a = false, b = true, c = true; + a and (b bitor c); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and (b or c); + (b bitor c) and a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b or c) and a; + + bool q = (true and (false bitor true)) and ((false bitor true) and (false and (true bitor false))); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:56: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:89: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool q = (true and (false or true)) and ((false or true) and (false and (true or false))); + + a xor (b bitand c); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a xor (b and c); + + a bitor (b bitand c); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a or (b and c); + + (b bitand c) xor a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b and c) xor a; + + (b bitand c) bitor a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b and c) or a; +} + +void bad_with_priors_compound() { + bool a = false, b = true, c = true; + a and_eq b or c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a and (b or c); + a or_eq b or c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a or b or c; + a and_eq b and c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a and b and c; + a or_eq b and c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a or b and c; +} + +void bad_with_priors_compound_already_braced() { + bool a = false, b = true, c = true; + a and_eq (b or c); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a and (b or c); +} + +void bad_no_fixit() { + bool b = false; + normal() or_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + normal() and_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} + +#define MY_OR bitor +#define MY_AND bitand +#define MY_OR_ASSIGN or_eq +#define MY_AND_ASSIGN and_eq +#define MY_LOG_AND and + +#define CAT(a, b) a ## b +#define IDENT(a) a + +void bad_in_macro() { + bool a = true, b = false; + + // change operator - BAD + IDENT(a bitor) b; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a IDENT(bitand b); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + IDENT(a or_eq) b; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a IDENT(and_eq b); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // change operator - GOOD + IDENT(a) bitor b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a) or b; + a bitand IDENT(b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and IDENT(b); + IDENT(a) bitand IDENT(b); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a) and IDENT(b); + + // insert `)` - BAD + bool c = true, e = false; + a and b bitor IDENT(c and) e; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // insert `)` - GOOD + a and b bitor c IDENT(and e); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a and (b or c) IDENT(and e); + + // insert `(` - BAD + a IDENT(and b) bitor c and e; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // insert `(` - GOOD + IDENT(a and) b bitor c and e; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a and) (b or c) and e; + + bool ab = false; + // insert ` = a` - BAD + CAT(a, b) and_eq b; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // insert ` = a`- GOOD + b and_eq CAT(a, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = b and CAT(a, b); +} + +void bad_in_macro_fixit() { + bool a = true, b = false; + + // FIXME: implement fixit for all of these cases + + a MY_OR b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + a MY_AND b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + a MY_OR_ASSIGN b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + a MY_AND_ASSIGN b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + IDENT(a and_eq b); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] +} + +template +void good_in_unreachable_template(T a, T b) { + a bitor b; + a bitand b; + a or_eq b; + a and_eq b; +} + +template +int bad_in_template(T a, T b) { + bool c = false; + // FIXME: at least warning should be provided in these cases + // a bitor b; + // a bitand b; + // a or_eq b; + // a and_eq b; + // c and_eq a; + return 0; +} + +template +int bad_in_template_lambda_captured(T a, T b) { + [=] mutable { + bool c = false; + // FIXME: at least warning should be provided in these cases + // a bitor b; + // a bitand b; + // a or_eq b; + // b and_eq a; + }(); + return 0; +} + +int dummy = bad_in_template(true, false) + bad_in_template_lambda_captured(false, true); diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-not-only-bool-operand-compound.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-not-only-bool-operand-compound.cpp new file mode 100644 index 0000000000000..19d39bfad6fe6 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-not-only-bool-operand-compound.cpp @@ -0,0 +1,20 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +void general(unsigned flags, bool value) { + flags |= value; + + unsigned mask = 0b1100; + bool result = flags &= mask; + auto result2 = flags &= mask; + result = flags |= flags << 1; +} + +void assign_to_boolean(unsigned flags, bool value) { + value |= flags << 1; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: value = value || flags << 1; + value |= (flags << 1) | (flags << 2); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: value = value || (flags << 1) || (flags << 2); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-not-only-bool-operand.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-not-only-bool-operand.cpp new file mode 100644 index 0000000000000..f93297a42f686 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-not-only-bool-operand.cpp @@ -0,0 +1,235 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +// The case is taken from the real code in clang/lib/APINotes/APINotesWriter.cpp + +void general(unsigned flags, bool value) { + (flags << 1) | value; + flags = (flags << 1) | value; + flags = (flags << 1) | (flags << 2) | value; + flags = (flags << 1) | (flags << 2) | (flags << 4) | value; +} + +void take(bool value) {} + +// FIXME: implement `template` cases + +void assign_to_boolean(unsigned flags, bool value) { + struct A { bool a = true | 1; }; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct A { bool a = true || 1; }; + struct B { union { bool a = true | 1; }; }; + // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct B { union { bool a = true || 1; }; }; + bool result = (flags << 1) | value; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool result = (flags << 1) || value; + bool a = (flags << 2) | value, + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool a = (flags << 2) || value, + b = (flags << 4) | value, + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = (flags << 4) || value, + c = (flags << 8) | value; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: c = (flags << 8) || value; + result = (flags << 1) | value; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (flags << 1) || value; + take((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: take((flags << 1) || value); + result = (flags << 1) | (flags << 2) | value; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:42: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (flags << 1) || (flags << 2) || value; + result = (flags << 1) | (flags << 2) | (flags << 4) | value; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:42: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:57: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (flags << 1) || (flags << 2) || (flags << 4) || value; +} + +void assign_to_boolean_parens(unsigned flags, bool value) { + struct A { bool a = (true | 1); }; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct A { bool a = (true || 1); }; + struct B { union { bool a = (true | 1); }; }; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct B { union { bool a = (true || 1); }; }; + bool result = ((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool result = ((flags << 1) || value); + bool a = ((flags << 2) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool a = ((flags << 2) || value), + b = ((flags << 4) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = ((flags << 4) || value), + c = ((flags << 8) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: c = ((flags << 8) || value); + result = ((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = ((flags << 1) || value); + take(((flags << 1) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: take(((flags << 1) || value)); + result = ((flags << 1) | (flags << 2) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:43: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = ((flags << 1) || (flags << 2) || value); + result = ((flags << 1) | (flags << 2) | (flags << 4) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:43: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = ((flags << 1) || (flags << 2) || (flags << 4) || value); +} + +void assign_to_boolean_parens2(unsigned flags, bool value) { + struct A { bool a = ((true | 1)); }; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct A { bool a = ((true || 1)); }; + struct B { union { bool a = ((true | 1)); }; }; + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct B { union { bool a = ((true || 1)); }; }; + bool result = (((flags << 1) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool result = (((flags << 1) || value)); + bool a = (((flags << 2) | value)), + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool a = (((flags << 2) || value)), + b = (((flags << 4) | value)), + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = (((flags << 4) || value)), + c = (((flags << 8) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: c = (((flags << 8) || value)); + result = (((flags << 1) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (((flags << 1) || value)); + take((((flags << 1) | value))); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: take((((flags << 1) || value))); + result = (((flags << 1) | (flags << 2) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (((flags << 1) || (flags << 2) || value)); + result = (((flags << 1) | (flags << 2) | (flags << 4) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:59: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (((flags << 1) || (flags << 2) || (flags << 4) || value)); +} + +// functional cast +void assign_to_boolean_fcast(unsigned flags, bool value) { + struct A { bool a = bool(true | 1); }; + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct A { bool a = bool(true || 1); }; + struct B { union { bool a = bool(true | 1); }; }; + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct B { union { bool a = bool(true || 1); }; }; + bool result = bool((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool result = bool((flags << 1) || value); + bool a = bool((flags << 2) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool a = bool((flags << 2) || value), + b = bool((flags << 4) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = bool((flags << 4) || value), + c = bool((flags << 8) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: c = bool((flags << 8) || value); + result = bool((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = bool((flags << 1) || value); + take(bool((flags << 1) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: take(bool((flags << 1) || value)); + result = bool((flags << 1) | (flags << 2) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:47: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = bool((flags << 1) || (flags << 2) || value); + result = bool((flags << 1) | (flags << 2) | (flags << 4) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:47: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:62: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = bool((flags << 1) || (flags << 2) || (flags << 4) || value); +} + +// C-style cast +void assign_to_boolean_ccast(unsigned flags, bool value) { + struct A { bool a = (bool)(true | 1); }; + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct A { bool a = (bool)(true || 1); }; + struct B { union { bool a = (bool)(true | 1); }; }; + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct B { union { bool a = (bool)(true || 1); }; }; + bool result = (bool)((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool result = (bool)((flags << 1) || value); + bool a = (bool)((flags << 2) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool a = (bool)((flags << 2) || value), + b = (bool)((flags << 4) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = (bool)((flags << 4) || value), + c = (bool)((flags << 8) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: c = (bool)((flags << 8) || value); + result = (bool)((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (bool)((flags << 1) || value); + take(bool((flags << 1) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: take(bool((flags << 1) || value)); + result = (bool)((flags << 1) | (flags << 2) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:49: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (bool)((flags << 1) || (flags << 2) || value); + result = (bool)((flags << 1) | (flags << 2) | (flags << 4) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:49: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:64: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = (bool)((flags << 1) || (flags << 2) || (flags << 4) || value); +} + +// static_cast +void assign_to_boolean_scast(unsigned flags, bool value) { + struct A { bool a = static_cast(true | 1); }; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct A { bool a = static_cast(true || 1); }; + struct B { union { bool a = static_cast(true | 1); }; }; + // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: struct B { union { bool a = static_cast(true || 1); }; }; + bool result = static_cast((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:50: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool result = static_cast((flags << 1) || value); + bool a = static_cast((flags << 2) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool a = static_cast((flags << 2) || value), + b = static_cast((flags << 4) | value), + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = static_cast((flags << 4) || value), + c = static_cast((flags << 8) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: c = static_cast((flags << 8) || value); + result = static_cast((flags << 1) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = static_cast((flags << 1) || value); + take(static_cast((flags << 1) | value)); + // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: take(static_cast((flags << 1) || value)); + result = static_cast((flags << 1) | (flags << 2) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:60: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = static_cast((flags << 1) || (flags << 2) || value); + result = static_cast((flags << 1) | (flags << 2) | (flags << 4) | value); + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:60: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:75: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: result = static_cast((flags << 1) || (flags << 2) || (flags << 4) || value); +} + + diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-static-members.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-static-members.cpp new file mode 100644 index 0000000000000..90ede4115a43f --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-static-members.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +struct A { + static int first; + static bool second; +}; + +int A::first = 100; +bool A::second = false; + +void normal() { + int b = 200; + + A::first | b; + A::first & b; + A::first |= b; + A::first &= b; +} + +void bad() { + bool b = false; + + A::second | b; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: A::second || b; + A::second & b; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: A::second && b; + A::second |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: A::second = A::second || b; + A::second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: A::second = A::second && b; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-struct-members.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-struct-members.cpp new file mode 100644 index 0000000000000..464a0723d52f0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation-struct-members.cpp @@ -0,0 +1,143 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +struct A { + int first; + bool second; +}; + +void normal() { + A a {100, false}; + int b = 200; + + a.first | b; + a.first & b; + a.first |= b; + a.first &= b; +} + +void bad() { + A a {-1, true}; + bool b = false; + + a.second | b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a.second || b; + a.second & b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a.second && b; + a.second |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a.second = a.second || b; + a.second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a.second = a.second && b; +} + +void bad_two_lines() { + A a {-1, true}; + bool b = false; + + a. + second | b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: second || b; + a. + second & b; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: second && b; + a. + second |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: second = a.second || b; + a + . + second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: second = a.second && b; + a + .second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: .second = a.second && b; +} + +void bad_side_effects_volatile() { + volatile A a {-1, true}; + bool b = false; + + a.second | b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a.second & b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a.second |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a.second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} + +struct VolatileA { + volatile bool second; +}; + +void bad_side_effects_volatile2() { + VolatileA a {true}; + bool b = false; + + a.second | b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a.second & b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a.second |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a.second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} + +void bad_arrow() { + A a {-1, true}; + auto* pa = &a; + bool b = false; + + pa->second | b; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: pa->second || b; + pa->second & b; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: pa->second && b; + pa->second |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: pa->second = pa->second || b; + pa->second &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: pa->second = pa->second && b; +} + +struct B { + bool& access(); +}; + +void bad_no_fixit() { + B b; + bool c = false; + b.access() |= c; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + b.access() &= c; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + auto* pb = &b; + pb->access() |= c; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + pb->access() &= c; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation.c b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation.c new file mode 100644 index 0000000000000..ebafc19dca605 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation.c @@ -0,0 +1,26 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +void normal() { + int a = 100, b = 200; + + a | b; + a & b; + a |= b; + a &= b; +} + +void bad() { + _Bool a = 1, b = 0; + a | b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || b; + a & b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && b; + a |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || b; + a &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && b; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation.cpp new file mode 100644 index 0000000000000..6487026b07583 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/bool-bitwise-operation.cpp @@ -0,0 +1,409 @@ +// RUN: %check_clang_tidy %s misc-bool-bitwise-operation %t + +bool& normal() { + int a = 100, b = 200; + + a | b; + a & b; + a |= b; + a &= b; + + static bool st = false; + return st; +} + +bool bad() noexcept __attribute__((pure)) { + bool a = true, b = false; + a | b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || b; + a & b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && b; + a |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || b; + a &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && b; + + return true; +} + +bool global_1 = bad() | bad(); +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] +// CHECK-FIXES: bool global_1 = bad() || bad(); +bool global_2 = bad() & bad(); +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] +// CHECK-FIXES: bool global_2 = bad() && bad(); + +using Boolean = bool; + +bool bad_typedef() { + Boolean a = true, b = false; + a | b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || b; + a & b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && b; + a |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || b; + a &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && b; + return true; +} + +bool function_with_possible_side_effects(); + +void bad_side_effects() { + bool a = true, b = false; + + a | function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a & function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + function_with_possible_side_effects() | a; + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() || a; + + function_with_possible_side_effects() & a; + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() && a; + a |= function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a &= function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // count of evaluation with side effect remains the same, so the fixit will be provided + bool c = true; + + a || function_with_possible_side_effects() | c; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || function_with_possible_side_effects() || c; + + function_with_possible_side_effects() || b | c; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() || b || c; + + a && function_with_possible_side_effects() & c; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && function_with_possible_side_effects() && c; + + function_with_possible_side_effects() && b & c; + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: function_with_possible_side_effects() && b && c; + + // but here the count of evaluation migh be changed - no fix must be provided + + a &= function_with_possible_side_effects() && c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a &= b && function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a |= function_with_possible_side_effects() || c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a |= b || function_with_possible_side_effects(); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} + +void bad_side_effects_volatile() { + bool a = true; + volatile bool b = false; + bool c = true; + + a | b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a & b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + a |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + (a | c) | b; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (a || c) | b; + + a | c | b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || c | b; +} + +void bad_with_priors() { + bool a = false, b = true, c = true; + a && b | c; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && (b || c); + a && b & c; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && b && c; + a || b & c; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || b && c; + a || b | c; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || b || c; + b | c && a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b || c) && a; + + bool q = (true && false | true) && (false | true && (false && true | false)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:47: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:72: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool q = (true && (false || true)) && ((false || true) && (false && (true || false))); +} + +void bad_with_priors2() { + bool a = false, b = true, c = true; + a ^ b & c; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a ^ (b && c); + // braces added in the first change + a | b & c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || (b && c); + + b & c ^ a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b && c) ^ a; + + // braces added in the first change + b & c | a; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b && c) || a; +} + +template +T ident(T val) { return val; } + +// cases to check `hasAncestor` works as we expected: +void bad_has_ancestor() { + bool a = false, b = true, c = true; + bool d = false; + d ^ (a && b & c); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: d ^ (a && b && c); + + a ^ ident(b & c || a); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a ^ ident(b && c || a); + + a | ident(a ? b & c : c); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a | ident(a ? b && c : c); +} + +void bad_with_priors_already_braced() { + bool a = false, b = true, c = true; + a && (b | c); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && (b || c); + (b | c) && a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b || c) && a; + + bool q = (true && (false | true)) && ((false | true) && (false && (true | false))); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:50: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-3]]:77: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: bool q = (true && (false || true)) && ((false || true) && (false && (true || false))); + + a ^ (b & c); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a ^ (b && c); + + a | (b & c); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a || (b && c); + + (b & c) ^ a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b && c) ^ a; + + (b & c) | a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: (b && c) || a; +} + +void bad_with_priors_compound() { + bool a = false, b = true, c = true; + a &= b || c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && (b || c); + a |= b || c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || b || c; + a &= b && c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && b && c; + a |= b && c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a || b && c; +} + +void bad_with_priors_compound_already_braced() { + bool a = false, b = true, c = true; + a &= (b || c); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: a = a && (b || c); +} + +void bad_no_fixit() { + bool b = false; + normal() |= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + normal() &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes +} + +#define MY_OR | +#define MY_AND & +#define MY_OR_ASSIGN |= +#define MY_AND_ASSIGN &= +#define MY_LOG_AND && + +#define CAT(a, b) a ## b +#define IDENT(a) a + +void bad_in_macro() { + bool a = true, b = false; + + // change operator - BAD + IDENT(a |) b; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a IDENT(& b); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + IDENT(a |=) b; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + a IDENT(&= b); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // change operator - GOOD + IDENT(a) | b; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a) || b; + a & IDENT(b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && IDENT(b); + IDENT(a) & IDENT(b); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a) && IDENT(b); + + // insert `)` - BAD + bool c = true, e = false; + a && b | IDENT(c &&) e; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // insert `)` - GOOD + a && b | c IDENT(&& e); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: a && (b || c) IDENT(&& e); + + // insert `(` - BAD + a IDENT(&& b) | c && e; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // insert `(` - GOOD + IDENT(a &&) b | c && e; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + // CHECK-FIXES: IDENT(a &&) (b || c) && e; + + bool ab = false; + // insert ` = a` - BAD + CAT(a, b) &= b; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:{{.*}}: note: FIX-IT applied suggested code changes + + // insert ` = a`- GOOD + b &= CAT(a, b); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + // CHECK-FIXES: b = b && CAT(a, b); +} + +void bad_in_macro_fixit() { + bool a = true, b = false; + + // FIXME: implement fixit for all of these cases + + a MY_OR b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|' [misc-bool-bitwise-operation] + a MY_AND b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&' [misc-bool-bitwise-operation] + a MY_OR_ASSIGN b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '||' for boolean semantics instead of bitwise operator '|=' [misc-bool-bitwise-operation] + a MY_AND_ASSIGN b; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] + IDENT(a &= b); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use logical operator '&&' for boolean semantics instead of bitwise operator '&=' [misc-bool-bitwise-operation] +} + +template +void good_in_unreachable_template(T a, T b) { + a | b; + a & b; + a |= b; + a &= b; +} + +template +int bad_in_template(T a, T b) { + bool c = false; + // FIXME: at least warning should be provided in these cases + // a | b; + // a & b; + // a |= b; + // a &= b; + // c &= a; + return 0; +} + +template +int bad_in_template_lambda_captured(T a, T b) { + [=] mutable { + bool c = false; + // FIXME: at least warning should be provided in these cases + // a | b; + // a & b; + // a |= b; + // b &= a; + }(); + return 0; +} + +int dummy = bad_in_template(true, false) + bad_in_template_lambda_captured(false, true);