[clang-tidy] Enhance clang-tidy readability-simplify-boolean-expr...

Enhance clang-tidy readability-simplify-boolean-expr to handle 'if (e) return
true; return false;' and improve replacement expressions.

This changeset extends the simplify boolean expression check in clang-tidy to
simplify if (e) return true; return false; to return e; (note the lack of an
else clause on the if statement.) By default, chained conditional assignment is
left unchanged, unless a configuration parameter is set to non-zero to override
this behavior.

It also improves the handling of replacement expressions to apply
static_cast<bool>(expr) when expr is not of type bool.

http://reviews.llvm.org/D9810

Patch by Richard Thomson!

llvm-svn: 241155
diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h
index 365d821..ac38d23 100644
--- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h
@@ -34,9 +34,46 @@
 /// `if (e) return false; else return true;`   becomes `return !e;`
 /// `if (e) b = true; else b = false;`         becomes `b = e;`
 /// `if (e) b = false; else b = true;`         becomes `b = !e;`
+/// `if (e) return true; return false;`        becomes `return e;`
+/// `if (e) return false; return true;`        becomes `return !e;`
 ///
-/// Parenthesis from the resulting expression `e` are removed whenever
-/// possible.
+/// The resulting expression `e` is modified as follows:
+/// 1. Unnecessary parentheses around the expression are removed.
+/// 2. Negated applications of `!` are eliminated.
+/// 3. Negated applications of comparison operators are changed to use the
+///    opposite condition.
+/// 4. Implicit conversions of pointer to `bool` are replaced with explicit
+///    comparisons to `nullptr`.
+/// 5. Implicit casts to `bool` are replaced with explicit casts to `bool`.
+/// 6. Object expressions with `explicit operator bool` conversion operators
+///    are replaced with explicit casts to `bool`.
+///
+/// Examples:
+/// 1. The ternary assignment `bool b = (i < 0) ? true : false;` has redundant
+/// parentheses and becomes `bool b = i < 0;`.
+///
+/// 2. The conditional return `if (!b) return false; return true;` has an
+/// implied double negation and becomes `return b;`.
+///
+/// 3. The conditional return `if (i < 0) return false; return true;` becomes
+/// `return i >= 0;`.
+/// The conditional return `if (i != 0) return false; return true;` becomes
+/// `return i == 0;`.
+///
+/// 4. The conditional return `if (p) return true; return false;` has an
+/// implicit conversion of a pointer to `bool` and becomes
+/// `return p != nullptr;`.
+/// The ternary assignment `bool b = (i & 1) ? true : false;` has an implicit
+/// conversion of `i & 1` to `bool` and becomes
+/// `bool b = static_cast<bool>(i & 1);`.
+///
+/// 5. The conditional return `if (i & 1) return true; else return false;` has
+/// an implicit conversion of an integer quantity `i & 1` to `bool` and becomes
+/// `return static_cast<bool>(i & 1);`
+///
+/// 6. Given `struct X { explicit operator bool(); };`, and an instance `x` of
+/// `struct X`, the conditional return `if (x) return true; return false;`
+/// becomes `return static_cast<bool>(x);`
 ///
 /// When a conditional boolean return or assignment appears at the end of a
 /// chain of `if`, `else if` statements, the conditional statement is left
@@ -77,6 +114,9 @@
   void matchIfAssignsBool(ast_matchers::MatchFinder *Finder, bool Value,
                           StringRef Id);
 
+  void matchCompoundIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
+                                  StringRef Id);
+
   void
   replaceWithExpression(const ast_matchers::MatchFinder::MatchResult &Result,
                         const CXXBoolLiteralExpr *BoolLiteral, bool UseLHS,
@@ -103,6 +143,10 @@
   replaceWithAssignment(const ast_matchers::MatchFinder::MatchResult &Result,
                         const IfStmt *If, bool Negated = false);
 
+  void replaceCompoundReturnWithCondition(
+      const ast_matchers::MatchFinder::MatchResult &Result,
+      const CompoundStmt *Compound, bool Negated = false);
+
   const bool ChainedConditionalReturn;
   const bool ChainedConditionalAssignment;
 };