alexey.knyshev created this revision.
alexey.knyshev added reviewers: dcoughlin, dergachev.a, NoQ, zaks.anna, 
a.sidorin, kromanenkov.
Herald added subscribers: cfe-commits, mgorny.

Repository:
  rC Clang

https://reviews.llvm.org/D41308

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/BitwiseOpBoolArgChecker.cpp
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  test/Analysis/bitwise-op-bool-arg.cpp

Index: test/Analysis/bitwise-op-bool-arg.cpp
===================================================================
--- test/Analysis/bitwise-op-bool-arg.cpp
+++ test/Analysis/bitwise-op-bool-arg.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.BitwiseOpBoolArg -verify -x c++ %s
+
+bool getBool() {
+  return true;
+}
+
+bool boolBitwiseOr() {
+  bool v = true;
+  return v | 1; // expected-warning {{Boolean value met at the left side of the bitwise '|' operator}}
+}
+
+bool boolBitwiseAnd() {
+  return 2 & getBool(); // expected-warning {{Boolean value met at the right side of the bitwise '&' operator}}
+}
+
+bool ifBoolBitwise(bool v) {
+  if (v << 1) { // expected-warning {{Boolean value met at the left side of the bitwise '<<' operator}}
+    return true;
+  }
+  return false;
+}
+
+bool ifBoolAnd(bool x, bool y) {
+  if (x && y) { // no-warning
+    return false;
+  }
+  return !y;
+}
+
+int bitwiseInt(int x, int y) {
+  return x | y; // no-warning
+}
+
+int bitwiseBoolCastedToIntOne(bool x) {
+  return (int)x | 1; // no-warning
+}
+
+int bitwiseBoolCastedToIntBoth(bool x, bool y) {
+  return (int)x & (int)y; // no-warning
+}
+
+int bitwiseImplCast(int x, int y) {
+  return !x & !y; // expected-warning {{Bitwise '&' operator is applied to Boolean values. Did you mean '&&'?}}
+}
+
+bool logicalImplCast(int x, int y) {
+  return !x && !y; // no-warning
+}
+
+bool ifBoolBitwiseAnd(bool x, bool y) {
+  if ((x && y) & (x || y)) { // expected-warning {{Bitwise '&' operator is applied to Boolean values. Did you mean '&&'?}}
+    return x || y;
+  }
+  return !(x && y);
+}
+
+bool ifBoolBitwiseNot(bool x) {
+  return ~x; // expected-warning {{Bitwise '~' operator is applied to Boolean value. Did you mean '!'?}}
+}
Index: lib/StaticAnalyzer/Checkers/BitwiseOpBoolArgChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/BitwiseOpBoolArgChecker.cpp
+++ lib/StaticAnalyzer/Checkers/BitwiseOpBoolArgChecker.cpp
@@ -0,0 +1,145 @@
+//== BitwiseOpBoolArgChecker.cpp - Check for bit ops on booleans -*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines BitwiseOpBoolArgChecker, which looks for bitwise operations
+// performed on boolean values and suggests using logical operators instead
+// where appropriate.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+
+using namespace clang;
+using namespace ento;
+using namespace ast_matchers;
+
+namespace {
+class BitwiseOpBoolArgChecker : public Checker<check::ASTCodeBody> {
+public:
+  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+                        BugReporter &BR) const;
+};
+
+class Callback : public MatchFinder::MatchCallback {
+  const CheckerBase *C;
+  BugReporter &BR;
+  AnalysisDeclContext *AC;
+
+  void report(const BinaryOperator *BO);
+  void report(const UnaryOperator *UO);
+
+public:
+  Callback(const CheckerBase *C, BugReporter &BR, AnalysisDeclContext *AC)
+      : C(C), BR(BR), AC(AC) {}
+
+  virtual void run(const MatchFinder::MatchResult &Result) override;
+};
+} // end anonymous namespace
+
+void BitwiseOpBoolArgChecker::checkASTCodeBody(const Decl *D,
+                                               AnalysisManager &Mgr,
+                                               BugReporter &BR) const {
+  auto BitwiseOpBool = stmt(eachOf(
+      forEachDescendant(
+          binaryOperator(
+              anyOf(hasOperatorName("|"), hasOperatorName("&"),
+                    hasOperatorName("<<"), hasOperatorName(">>"),
+                    hasOperatorName("^")),
+              eachOf(hasLHS(ignoringParenImpCasts(hasType(booleanType()))),
+                     hasRHS(ignoringParenImpCasts(hasType(booleanType())))))
+              .bind("binOp")),
+      forEachDescendant(unaryOperator(hasOperatorName("~"),
+                                      hasUnaryOperand(ignoringParenImpCasts(
+                                          hasType(booleanType()))))
+                            .bind("unOp"))));
+
+  MatchFinder F;
+  Callback CB(this, BR, Mgr.getAnalysisDeclContext(D));
+
+  F.addMatcher(BitwiseOpBool, &CB);
+  F.match(*D->getBody(), Mgr.getASTContext());
+}
+
+void Callback::report(const BinaryOperator *BO) {
+  const Expr *LHS = BO->getLHS();
+  const Expr *RHS = BO->getRHS();
+
+  QualType LType = LHS->IgnoreParenImpCasts()->getType();
+  QualType RType = RHS->IgnoreParenImpCasts()->getType();
+
+  const bool LBool = LType.isNull() ? false : LType->isBooleanType();
+  const bool RBool = RType.isNull() ? false : RType->isBooleanType();
+
+  StringRef OpcodeStr = BO->getOpcodeStr();
+
+  SmallString<96> Message;
+  llvm::raw_svector_ostream OS(Message);
+
+  SmallVector<SourceRange, 2> SourceRangeVec;
+  if (LBool && RBool) {
+    OS << "Bitwise '" << OpcodeStr
+       << "' operator is applied to Boolean values.";
+    if (BO->isBitwiseOp())
+      OS << " Did you mean '" << OpcodeStr << OpcodeStr << "'?";
+
+    SourceRangeVec.push_back(LHS->getSourceRange());
+    SourceRangeVec.push_back(RHS->getSourceRange());
+  } else {
+    OS << "Boolean value met at the ";
+    if (LBool) {
+      OS << "left";
+      SourceRangeVec.push_back(LHS->getSourceRange());
+    } else {
+      OS << "right";
+      SourceRangeVec.push_back(RHS->getSourceRange());
+    }
+    OS << " side of the bitwise '" << OpcodeStr << "' operator";
+  }
+
+  PathDiagnosticLocation Loc =
+      PathDiagnosticLocation::createOperatorLoc(BO, BR.getSourceManager());
+
+  BR.EmitBasicReport(AC->getDecl(), C, "Bitwise operation on Boolean value",
+                     categories::LogicError, Message, Loc, SourceRangeVec);
+}
+
+void Callback::report(const UnaryOperator *UO) {
+  SmallString<96> Message;
+  llvm::raw_svector_ostream OS(Message);
+  OS << "Bitwise '" << UnaryOperator::getOpcodeStr(UO->getOpcode())
+     << "' operator is applied to Boolean value. Did you mean '!'?";
+
+  PathDiagnosticLocation Loc =
+      PathDiagnosticLocation::createBegin(UO, BR.getSourceManager(), AC);
+
+  BR.EmitBasicReport(AC->getDecl(), C, "Bitwise operation on Boolean value",
+                     categories::LogicError, Message, Loc,
+                     UO->getSourceRange());
+}
+
+void Callback::run(const MatchFinder::MatchResult &Result) {
+  const BinaryOperator *BO = Result.Nodes.getNodeAs<BinaryOperator>("binOp");
+  if (BO)
+    report(BO);
+
+  const UnaryOperator *UO = Result.Nodes.getNodeAs<UnaryOperator>("unOp");
+  if (UO)
+    report(UO);
+}
+
+namespace clang {
+namespace ento {
+void registerBitwiseOpBoolArgChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<BitwiseOpBoolArgChecker>();
+}
+} // namespace ento
+} // namespace clang
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -9,6 +9,7 @@
   ArrayBoundChecker.cpp
   ArrayBoundCheckerV2.cpp
   BasicObjCFoundationChecks.cpp
+  BitwiseOpBoolArgChecker.cpp
   BlockInCriticalSectionChecker.cpp
   BoolAssignmentChecker.cpp
   BuiltinFunctionChecker.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -140,6 +140,10 @@
 
 let ParentPackage = CoreAlpha in {
 
+def BitwiseOpBoolArgChecker : Checker<"BitwiseOpBoolArg">,
+  HelpText<"Warn about bitwise operations performed on Booleans">,
+  DescFile<"BitwiseOpBoolArgChecker.cpp">;
+
 def BoolAssignmentChecker : Checker<"BoolAssignment">,
   HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
   DescFile<"BoolAssignmentChecker.cpp">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D41308: [analyser] ... Alexey Knyshev via Phabricator via cfe-commits

Reply via email to