[clang-tools-extra] r303081 - [clang-tidy] Partly rewrite readability-simplify-boolean-expr using RAV

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Mon May 15 10:06:51 PDT 2017


Author: alexfh
Date: Mon May 15 12:06:51 2017
New Revision: 303081

URL: http://llvm.org/viewvc/llvm-project?rev=303081&view=rev
Log:
[clang-tidy] Partly rewrite readability-simplify-boolean-expr using RAV

The check was using AST matchers in a very inefficient manner. By rewriting the
BinaryOperator-related parts using RAV, the check was sped up by a factor of
up to 10000 on some files (mostly, generated code using binary operators in
tables), but also significantly sped up for regular large files.
As a side effect, the code became clearer and more readable.

Modified:
    clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
    clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.h

Modified: clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp?rev=303081&r1=303080&r2=303081&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.cpp Mon May 15 12:06:51 2017
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SimplifyBooleanExprCheck.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Lex/Lexer.h"
 
 #include <cassert>
@@ -33,10 +34,6 @@ StringRef getText(const MatchFinder::Mat
   return getText(Result, Node.getSourceRange());
 }
 
-const char RightExpressionId[] = "bool-op-expr-yields-expr";
-const char LeftExpressionId[] = "expr-op-bool-yields-expr";
-const char NegatedRightExpressionId[] = "bool-op-expr-yields-not-expr";
-const char NegatedLeftExpressionId[] = "expr-op-bool-yields-not-expr";
 const char ConditionThenStmtId[] = "if-bool-yields-then";
 const char ConditionElseStmtId[] = "if-bool-yields-else";
 const char TernaryId[] = "ternary-bool-yields-condition";
@@ -54,8 +51,6 @@ const char CompoundBoolId[] = "compound-
 const char CompoundNotBoolId[] = "compound-bool-not";
 
 const char IfStmtId[] = "if";
-const char LHSId[] = "lhs-expr";
-const char RHSId[] = "rhs-expr";
 
 const char SimplifyOperatorDiagnostic[] =
     "redundant boolean literal supplied to boolean operator";
@@ -323,6 +318,25 @@ bool containsDiscardedTokens(const Match
 
 } // namespace
 
+class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
+  using Base = RecursiveASTVisitor<Visitor>;
+
+ public:
+  Visitor(SimplifyBooleanExprCheck *Check,
+          const MatchFinder::MatchResult &Result)
+      : Check(Check), Result(Result) {}
+
+  bool VisitBinaryOperator(BinaryOperator *Op) {
+    Check->reportBinOp(Result, Op);
+    return true;
+  }
+
+ private:
+  SimplifyBooleanExprCheck *Check;
+  const MatchFinder::MatchResult &Result;
+};
+
+
 SimplifyBooleanExprCheck::SimplifyBooleanExprCheck(StringRef Name,
                                                    ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
@@ -330,63 +344,82 @@ SimplifyBooleanExprCheck::SimplifyBoolea
       ChainedConditionalAssignment(
           Options.get("ChainedConditionalAssignment", 0U)) {}
 
-void SimplifyBooleanExprCheck::matchBoolBinOpExpr(MatchFinder *Finder,
-                                                  bool Value,
-                                                  StringRef OperatorName,
-                                                  StringRef BooleanId) {
-  Finder->addMatcher(
-      binaryOperator(
-          isExpansionInMainFile(), hasOperatorName(OperatorName),
-          hasLHS(allOf(expr().bind(LHSId),
-                       cxxBoolLiteral(equals(Value)).bind(BooleanId))),
-          hasRHS(expr().bind(RHSId)),
-          unless(hasRHS(hasDescendant(cxxBoolLiteral())))),
-      this);
+bool containsBoolLiteral(const Expr *E) {
+  if (!E)
+    return false;
+  E = E->IgnoreParenImpCasts();
+  if (isa<CXXBoolLiteralExpr>(E))
+    return true;
+  if (const auto *BinOp = dyn_cast<BinaryOperator>(E))
+    return containsBoolLiteral(BinOp->getLHS()) ||
+           containsBoolLiteral(BinOp->getRHS());
+  if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E))
+    return containsBoolLiteral(UnaryOp->getSubExpr());
+  return false;
 }
 
-void SimplifyBooleanExprCheck::matchExprBinOpBool(MatchFinder *Finder,
-                                                  bool Value,
-                                                  StringRef OperatorName,
-                                                  StringRef BooleanId) {
-  Finder->addMatcher(
-      binaryOperator(
-          isExpansionInMainFile(), hasOperatorName(OperatorName),
-          hasLHS(expr().bind(LHSId)),
-          unless(
-              hasLHS(anyOf(cxxBoolLiteral(), hasDescendant(cxxBoolLiteral())))),
-          hasRHS(allOf(expr().bind(RHSId),
-                       cxxBoolLiteral(equals(Value)).bind(BooleanId)))),
-      this);
-}
+void SimplifyBooleanExprCheck::reportBinOp(
+    const MatchFinder::MatchResult &Result, const BinaryOperator *Op) {
+  const auto *LHS = Op->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = Op->getRHS()->IgnoreParenImpCasts();
+
+  const CXXBoolLiteralExpr *Bool = nullptr;
+  const Expr *Other = nullptr;
+  if ((Bool = dyn_cast<CXXBoolLiteralExpr>(LHS)))
+    Other = RHS;
+  else if ((Bool = dyn_cast<CXXBoolLiteralExpr>(RHS)))
+    Other = LHS;
+  else
+    return;
 
-void SimplifyBooleanExprCheck::matchBoolCompOpExpr(MatchFinder *Finder,
-                                                   bool Value,
-                                                   StringRef OperatorName,
-                                                   StringRef BooleanId) {
-  Finder->addMatcher(
-      binaryOperator(
-          isExpansionInMainFile(), hasOperatorName(OperatorName),
-          hasLHS(allOf(
-              expr().bind(LHSId),
-              ignoringImpCasts(cxxBoolLiteral(equals(Value)).bind(BooleanId)))),
-          hasRHS(expr().bind(RHSId)),
-          unless(hasRHS(hasDescendant(cxxBoolLiteral())))),
-      this);
-}
+  if (Bool->getLocStart().isMacroID())
+    return;
 
-void SimplifyBooleanExprCheck::matchExprCompOpBool(MatchFinder *Finder,
-                                                   bool Value,
-                                                   StringRef OperatorName,
-                                                   StringRef BooleanId) {
-  Finder->addMatcher(
-      binaryOperator(
-          isExpansionInMainFile(), hasOperatorName(OperatorName),
-          unless(hasLHS(hasDescendant(cxxBoolLiteral()))),
-          hasLHS(expr().bind(LHSId)),
-          hasRHS(allOf(expr().bind(RHSId),
-                       ignoringImpCasts(
-                           cxxBoolLiteral(equals(Value)).bind(BooleanId))))),
-      this);
+  // FIXME: why do we need this?
+  if (!isa<CXXBoolLiteralExpr>(Other) && containsBoolLiteral(Other))
+    return;
+
+  bool BoolValue = Bool->getValue();
+
+  auto replaceWithExpression = [this, &Result, LHS, RHS, Bool](
+                                   const Expr *ReplaceWith, bool Negated) {
+    std::string Replacement =
+        replacementExpression(Result, Negated, ReplaceWith);
+    SourceRange Range(LHS->getLocStart(), RHS->getLocEnd());
+    issueDiag(Result, Bool->getLocStart(), SimplifyOperatorDiagnostic, Range,
+              Replacement);
+  };
+
+  switch (Op->getOpcode()) {
+    case BO_LAnd:
+      if (BoolValue) {
+        // expr && true -> expr
+        replaceWithExpression(Other, /*Negated=*/false);
+      } else {
+        // expr && false -> false
+        replaceWithExpression(Bool, /*Negated=*/false);
+      }
+      break;
+    case BO_LOr:
+      if (BoolValue) {
+        // expr || true -> true
+        replaceWithExpression(Bool, /*Negated=*/false);
+      } else {
+        // expr || false -> expr
+        replaceWithExpression(Other, /*Negated=*/false);
+      }
+      break;
+    case BO_EQ:
+      // expr == true -> expr, expr == false -> !expr
+      replaceWithExpression(Other, /*Negated=*/!BoolValue);
+      break;
+    case BO_NE:
+      // expr != true -> !expr, expr != false -> expr
+      replaceWithExpression(Other, /*Negated=*/BoolValue);
+      break;
+    default:
+      break;
+  }
 }
 
 void SimplifyBooleanExprCheck::matchBoolCondition(MatchFinder *Finder,
@@ -475,25 +508,7 @@ void SimplifyBooleanExprCheck::storeOpti
 }
 
 void SimplifyBooleanExprCheck::registerMatchers(MatchFinder *Finder) {
-  matchBoolBinOpExpr(Finder, true, "&&", RightExpressionId);
-  matchBoolBinOpExpr(Finder, false, "||", RightExpressionId);
-  matchExprBinOpBool(Finder, false, "&&", RightExpressionId);
-  matchExprBinOpBool(Finder, true, "||", RightExpressionId);
-  matchBoolCompOpExpr(Finder, true, "==", RightExpressionId);
-  matchBoolCompOpExpr(Finder, false, "!=", RightExpressionId);
-
-  matchExprBinOpBool(Finder, true, "&&", LeftExpressionId);
-  matchExprBinOpBool(Finder, false, "||", LeftExpressionId);
-  matchBoolBinOpExpr(Finder, false, "&&", LeftExpressionId);
-  matchBoolBinOpExpr(Finder, true, "||", LeftExpressionId);
-  matchExprCompOpBool(Finder, true, "==", LeftExpressionId);
-  matchExprCompOpBool(Finder, false, "!=", LeftExpressionId);
-
-  matchBoolCompOpExpr(Finder, false, "==", NegatedRightExpressionId);
-  matchBoolCompOpExpr(Finder, true, "!=", NegatedRightExpressionId);
-
-  matchExprCompOpBool(Finder, false, "==", NegatedLeftExpressionId);
-  matchExprCompOpBool(Finder, true, "!=", NegatedLeftExpressionId);
+  Finder->addMatcher(translationUnitDecl().bind("top"), this);
 
   matchBoolCondition(Finder, true, ConditionThenStmtId);
   matchBoolCondition(Finder, false, ConditionElseStmtId);
@@ -512,20 +527,8 @@ void SimplifyBooleanExprCheck::registerM
 }
 
 void SimplifyBooleanExprCheck::check(const MatchFinder::MatchResult &Result) {
-  if (const CXXBoolLiteralExpr *LeftRemoved =
-          getBoolLiteral(Result, RightExpressionId))
-    replaceWithExpression(Result, LeftRemoved, false);
-  else if (const CXXBoolLiteralExpr *RightRemoved =
-               getBoolLiteral(Result, LeftExpressionId))
-    replaceWithExpression(Result, RightRemoved, true);
-  else if (const CXXBoolLiteralExpr *NegatedLeftRemoved =
-               getBoolLiteral(Result, NegatedRightExpressionId))
-    replaceWithExpression(Result, NegatedLeftRemoved, false, true);
-  else if (const CXXBoolLiteralExpr *NegatedRightRemoved =
-               getBoolLiteral(Result, NegatedLeftExpressionId))
-    replaceWithExpression(Result, NegatedRightRemoved, true, true);
-  else if (const CXXBoolLiteralExpr *TrueConditionRemoved =
-               getBoolLiteral(Result, ConditionThenStmtId))
+  if (const CXXBoolLiteralExpr *TrueConditionRemoved =
+          getBoolLiteral(Result, ConditionThenStmtId))
     replaceWithThenStatement(Result, TrueConditionRemoved);
   else if (const CXXBoolLiteralExpr *FalseConditionRemoved =
                getBoolLiteral(Result, ConditionElseStmtId))
@@ -553,6 +556,8 @@ void SimplifyBooleanExprCheck::check(con
   else if (const auto *Compound =
                Result.Nodes.getNodeAs<CompoundStmt>(CompoundNotBoolId))
     replaceCompoundReturnWithCondition(Result, Compound, true);
+  else if (const auto TU = Result.Nodes.getNodeAs<Decl>("top"))
+    Visitor(this, Result).TraverseDecl(const_cast<Decl*>(TU));
 }
 
 void SimplifyBooleanExprCheck::issueDiag(
@@ -568,18 +573,6 @@ void SimplifyBooleanExprCheck::issueDiag
     Diag << FixItHint::CreateReplacement(CharRange, Replacement);
 }
 
-void SimplifyBooleanExprCheck::replaceWithExpression(
-    const ast_matchers::MatchFinder::MatchResult &Result,
-    const CXXBoolLiteralExpr *BoolLiteral, bool UseLHS, bool Negated) {
-  const auto *LHS = Result.Nodes.getNodeAs<Expr>(LHSId);
-  const auto *RHS = Result.Nodes.getNodeAs<Expr>(RHSId);
-  std::string Replacement =
-      replacementExpression(Result, Negated, UseLHS ? LHS : RHS);
-  SourceRange Range(LHS->getLocStart(), RHS->getLocEnd());
-  issueDiag(Result, BoolLiteral->getLocStart(), SimplifyOperatorDiagnostic,
-            Range, Replacement);
-}
-
 void SimplifyBooleanExprCheck::replaceWithThenStatement(
     const MatchFinder::MatchResult &Result,
     const CXXBoolLiteralExpr *TrueConditionRemoved) {

Modified: clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.h?rev=303081&r1=303080&r2=303081&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.h (original)
+++ clang-tools-extra/trunk/clang-tidy/readability/SimplifyBooleanExprCheck.h Mon May 15 12:06:51 2017
@@ -30,17 +30,10 @@ public:
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
 private:
-  void matchBoolBinOpExpr(ast_matchers::MatchFinder *Finder, bool Value,
-                          StringRef OperatorName, StringRef BooleanId);
+  class Visitor;
 
-  void matchExprBinOpBool(ast_matchers::MatchFinder *Finder, bool Value,
-                          StringRef OperatorName, StringRef BooleanId);
-
-  void matchBoolCompOpExpr(ast_matchers::MatchFinder *Finder, bool Value,
-                           StringRef OperatorName, StringRef BooleanId);
-
-  void matchExprCompOpBool(ast_matchers::MatchFinder *Finder, bool Value,
-                           StringRef OperatorName, StringRef BooleanId);
+  void reportBinOp(const ast_matchers::MatchFinder::MatchResult &Result,
+                   const BinaryOperator *Op);
 
   void matchBoolCondition(ast_matchers::MatchFinder *Finder, bool Value,
                           StringRef BooleanId);
@@ -58,11 +51,6 @@ private:
                                   StringRef Id);
 
   void
-  replaceWithExpression(const ast_matchers::MatchFinder::MatchResult &Result,
-                        const CXXBoolLiteralExpr *BoolLiteral, bool UseLHS,
-                        bool Negated = false);
-
-  void
   replaceWithThenStatement(const ast_matchers::MatchFinder::MatchResult &Result,
                            const CXXBoolLiteralExpr *BoolLiteral);
 




More information about the cfe-commits mailing list