Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -9,6 +9,7 @@ ReadabilityTidyModule.cpp RedundantSmartptrGet.cpp ShrinkToFitCheck.cpp + SimplifyBooleanExpr.cpp LINK_LIBS clangAST Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -16,6 +16,7 @@ #include "FunctionSize.h" #include "RedundantSmartptrGet.h" #include "ShrinkToFitCheck.h" +#include "SimplifyBooleanExpr.h" namespace clang { namespace tidy { @@ -36,6 +37,8 @@ "readability-redundant-smartptr-get"); CheckFactories.registerCheck( "readability-shrink-to-fit"); + CheckFactories.registerCheck( + "readability-simplify-boolean-expr"); } }; Index: clang-tidy/readability/SimplifyBooleanExpr.h =================================================================== --- /dev/null +++ clang-tidy/readability/SimplifyBooleanExpr.h @@ -0,0 +1,103 @@ +//===--- SimplifyBooleanExpr.h clang-tidy -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief Replace copy and swap tricks on shrinkable containers with the +/// \c shrink_to_fit() method call. +/// +/// The \c shrink_to_fit() method is more readable and more effective than +/// the copy and swap trick to reduce the capacity of a shrinkable container. +/// Note that, the \c shrink_to_fit() method is only available in C++11 and up. +class SimplifyBooleanExpr : public ClangTidyCheck { +public: + SimplifyBooleanExpr(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void matchBoolBinOpExpr( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId); + + void matchExprBinOpBool( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId); + + void matchBoolCompOpExpr( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId); + + void matchExprCompOpBool( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId); + + void matchBoolCondition( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const BooleanId); + + void matchTernaryResult( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const TernaryId); + + void replaceWithRightExpression( + const ast_matchers::MatchFinder::MatchResult &Result, + Expr const *BoolLiteral, + std::string Prefix = ""); + + void replaceWithLeftBooleanLiteral( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral); + + void replaceWithRightBooleanLiteral( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral); + + void replaceWithLeftExpression( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral, + std::string Prefix = ""); + + void replaceWithThenStatement( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral); + + void replaceWithElseStatement( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *FalseConditionRemoved); + + void replaceWithCondition( + const ast_matchers::MatchFinder::MatchResult &Result, + ConditionalOperator const *Ternary, + std::string Prefix = ""); +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H Index: clang-tidy/readability/SimplifyBooleanExpr.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/SimplifyBooleanExpr.cpp @@ -0,0 +1,328 @@ +//===--- SimplifyBooleanExpr.cpp clang-tidy ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SimplifyBooleanExpr.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +#include + +using namespace clang; +using namespace clang::ast_matchers; + +namespace { + +inline std::string getText( + const ast_matchers::MatchFinder::MatchResult &Result, + SourceRange Range) { + return Lexer::getSourceText( + CharSourceRange::getTokenRange(Range), + *Result.SourceManager, Result.Context->getLangOpts()); +} + +template +std::string getText(const ast_matchers::MatchFinder::MatchResult &Result, T &Node) { + return getText(Result, Node.getSourceRange()); +} + +char const *const LeftBooleanLiteralId = "bool-op-expr-yields-bool"; +char const *const RightExpressionId = "bool-op-expr-yields-expr"; +char const *const RightBooleanLiteralId = "expr-op-bool-yields-bool"; +char const *const LeftExpressionId = "expr-op-bool-yields-expr"; +char const *const NegatedRightExpressionId = "bool-op-expr-yields-not-expr"; +char const *const NegatedLeftExpressionId = "expr-op-bool-yields-not-expr"; +char const *const ConditionThenStmtId = "if-bool-yields-then"; +char const *const ConditionElseStmtId = "if-bool-yields-else"; +char const *const TernaryId = "ternary-bool-yields-condition"; +char const *const TernaryNegatedId = "ternary-bool-yields-not-condition"; + +char const *const IfStmtId = "if"; +char const *const ExpressionId = "expr"; + +char const *const SimplifyDiagnostic = "Redundant boolean constant supplied to boolean operator."; +char const *const SimplifyConditionDiagnostic = "Redundant boolean constant in if statement condition."; + +inline CXXBoolLiteralExpr const *getBoolLiteral( + const BoundNodes &Nodes, + const char *const FirstId) +{ + return Nodes.getNodeAs(FirstId); +} + +inline CXXBoolLiteralExpr const *getLeftRemoved(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, RightExpressionId); +} + +inline CXXBoolLiteralExpr const *getLeftReplacing(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, LeftBooleanLiteralId); +} + +inline CXXBoolLiteralExpr const *getRightReplacing(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, RightBooleanLiteralId); +} + +inline CXXBoolLiteralExpr const *getRightRemoved(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, LeftExpressionId); +} + +inline CXXBoolLiteralExpr const *getNegatedLeftRemoved(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, NegatedRightExpressionId); +} + +inline CXXBoolLiteralExpr const *getNegatedRightRemoved(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, NegatedLeftExpressionId); +} + +inline CXXBoolLiteralExpr const *getTrueConditionRemoved(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, ConditionThenStmtId); +} + +inline CXXBoolLiteralExpr const *getFalseConditionRemoved(MatchFinder::MatchResult const &Result) +{ + return getBoolLiteral(Result.Nodes, ConditionElseStmtId); +} + +} // namespace + +namespace clang { +namespace tidy { +namespace readability { + +void SimplifyBooleanExpr::matchBoolBinOpExpr( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId) { + Finder->addMatcher( + binaryOperator( + isExpansionInMainFile(), + hasOperatorName(OperatorName), + hasLHS(boolLiteral(equals(Value)).bind(BooleanId)), + hasRHS(expr().bind(ExpressionId)), + unless(hasRHS(hasDescendant(boolLiteral()))) + ), this); +} + +void SimplifyBooleanExpr::matchExprBinOpBool( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId) { + Finder->addMatcher( + binaryOperator( + isExpansionInMainFile(), + hasOperatorName(OperatorName), + hasLHS(expr().bind(ExpressionId)), + unless(hasLHS(boolLiteral())), + unless(hasLHS(hasDescendant(boolLiteral()))), + hasRHS(boolLiteral(equals(Value)).bind(BooleanId)) + ), this); +} + +void SimplifyBooleanExpr::matchBoolCompOpExpr( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId) { + Finder->addMatcher( + binaryOperator( + isExpansionInMainFile(), + hasOperatorName(OperatorName), + hasLHS(hasDescendant(boolLiteral(equals(Value)).bind(BooleanId))), + hasRHS(expr().bind(ExpressionId)), + unless(hasRHS(hasDescendant(boolLiteral()))) + ), this); +} + +void SimplifyBooleanExpr::matchExprCompOpBool( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const OperatorName, + char const *const BooleanId) { + Finder->addMatcher( + binaryOperator( + isExpansionInMainFile(), + hasOperatorName(OperatorName), + hasLHS(expr().bind(ExpressionId)), + unless(hasLHS(boolLiteral())), + unless(hasLHS(hasDescendant(boolLiteral()))), + hasRHS(hasDescendant(boolLiteral(equals(Value)).bind(BooleanId))) + ), this); +} + +void SimplifyBooleanExpr::matchBoolCondition( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const BooleanId) { + Finder->addMatcher( + ifStmt( + isExpansionInMainFile(), + hasCondition(boolLiteral(equals(Value)).bind(BooleanId)) + ).bind(IfStmtId), this); +} + +void SimplifyBooleanExpr::matchTernaryResult( + ast_matchers::MatchFinder *Finder, + bool Value, + char const *const TernaryId) { + Finder->addMatcher( + conditionalOperator( + isExpansionInMainFile(), + hasTrueExpression(boolLiteral(equals(Value))), + hasFalseExpression(boolLiteral(equals(!Value))) + ).bind(TernaryId), this); +} + +void SimplifyBooleanExpr::registerMatchers(ast_matchers::MatchFinder *Finder) +{ + matchBoolBinOpExpr(Finder, true, "&&", RightExpressionId); + matchBoolBinOpExpr(Finder, false, "||", RightExpressionId); + matchBoolCompOpExpr(Finder, true, "==", RightExpressionId); + matchBoolCompOpExpr(Finder, false, "!=", RightExpressionId); + + matchBoolBinOpExpr(Finder, false, "&&", LeftBooleanLiteralId); + matchBoolBinOpExpr(Finder, true, "||", LeftBooleanLiteralId); + + matchExprBinOpBool(Finder, false, "&&", RightBooleanLiteralId); + matchExprBinOpBool(Finder, true, "||", RightBooleanLiteralId); + + matchExprBinOpBool(Finder, true, "&&", LeftExpressionId); + matchExprBinOpBool(Finder, false, "||", 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); + + matchBoolCondition(Finder, true, ConditionThenStmtId); + matchBoolCondition(Finder, false, ConditionElseStmtId); + + matchTernaryResult(Finder, true, TernaryId); + matchTernaryResult(Finder, false, TernaryNegatedId); +} + +void SimplifyBooleanExpr::check(const ast_matchers::MatchFinder::MatchResult &Result) +{ + if (auto LeftRemoved = getLeftRemoved(Result)) { + replaceWithRightExpression(Result, LeftRemoved); + } else if (auto LeftReplacing = getLeftReplacing(Result)) { + replaceWithLeftBooleanLiteral(Result, LeftReplacing); + } else if (auto RightReplacing = getRightReplacing(Result)) { + replaceWithRightBooleanLiteral(Result, RightReplacing); + } else if (auto RightRemoved = getRightRemoved(Result)) { + replaceWithLeftExpression(Result, RightRemoved); + } else if (auto NegatedLeftRemoved = getNegatedLeftRemoved(Result)) { + replaceWithRightExpression(Result, NegatedLeftRemoved, "!"); + } else if (auto NegatedRightRemoved = getNegatedRightRemoved(Result)) { + replaceWithLeftExpression(Result, NegatedRightRemoved, "!"); + } else if (auto TrueConditionRemoved = getTrueConditionRemoved(Result)) { + replaceWithThenStatement(Result, TrueConditionRemoved); + } else if (auto FalseConditionRemoved = getFalseConditionRemoved(Result)) { + replaceWithElseStatement(Result, FalseConditionRemoved); + } else if (auto Ternary = Result.Nodes.getNodeAs(TernaryId)) { + replaceWithCondition(Result, Ternary); + } else if (auto TernaryNegated = Result.Nodes.getNodeAs(TernaryNegatedId)) { + replaceWithCondition(Result, TernaryNegated, "!"); + } +} + +void SimplifyBooleanExpr::replaceWithRightExpression( + const ast_matchers::MatchFinder::MatchResult &Result, + Expr const *BoolLiteral, + std::string const Prefix) +{ + auto const *const Expression = Result.Nodes.getNodeAs(ExpressionId); + diag(BoolLiteral->getLocStart(), SimplifyDiagnostic) + << FixItHint::CreateReplacement( + SourceRange(BoolLiteral->getLocStart(), Expression->getLocEnd()), + Prefix + getText(Result, *Expression)); +} + +void SimplifyBooleanExpr::replaceWithLeftBooleanLiteral( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral) +{ + auto const *const Expression = Result.Nodes.getNodeAs(ExpressionId); + diag(BoolLiteral->getLocStart(), SimplifyDiagnostic) + << FixItHint::CreateReplacement( + SourceRange(BoolLiteral->getLocStart(), Expression->getLocEnd()), + getText(Result, *BoolLiteral)); +} + +void SimplifyBooleanExpr::replaceWithRightBooleanLiteral( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral) +{ + auto const *const Expression = Result.Nodes.getNodeAs(ExpressionId); + diag(BoolLiteral->getLocStart(), SimplifyDiagnostic) + << FixItHint::CreateReplacement( + SourceRange(Expression->getLocStart(), BoolLiteral->getLocEnd()), + getText(Result, *BoolLiteral)); +} + +void SimplifyBooleanExpr::replaceWithLeftExpression( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *BoolLiteral, + std::string const Prefix) +{ + auto const *const Expression = Result.Nodes.getNodeAs(ExpressionId); + diag(BoolLiteral->getLocStart(), SimplifyDiagnostic) + << FixItHint::CreateReplacement( + SourceRange(Expression->getLocStart(), BoolLiteral->getLocEnd()), + Prefix + getText(Result, *Expression)); +} + +void SimplifyBooleanExpr::replaceWithThenStatement( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *TrueConditionRemoved) +{ + auto const *const IfStatement = Result.Nodes.getNodeAs(IfStmtId); + diag(TrueConditionRemoved->getLocStart(), SimplifyConditionDiagnostic) + << FixItHint::CreateReplacement( + IfStatement->getSourceRange(), + getText(Result, *IfStatement->getThen())); +} + +void SimplifyBooleanExpr::replaceWithElseStatement( + const ast_matchers::MatchFinder::MatchResult &Result, + CXXBoolLiteralExpr const *FalseConditionRemoved) +{ + auto const *const IfStatement = Result.Nodes.getNodeAs(IfStmtId); + auto const *const ElseStatement = IfStatement->getElse(); + diag(FalseConditionRemoved->getLocStart(), SimplifyConditionDiagnostic) + << FixItHint::CreateReplacement( + IfStatement->getSourceRange(), + ElseStatement ? getText(Result, *ElseStatement) : ""); +} + +void SimplifyBooleanExpr::replaceWithCondition( + const ast_matchers::MatchFinder::MatchResult &Result, + ConditionalOperator const *Ternary, + std::string Prefix) +{ + diag(Ternary->getTrueExpr()->getLocStart(), + "Redundant boolean literal in ternary expression result.") + << FixItHint::CreateReplacement( + Ternary->getSourceRange(), + Prefix + getText(Result, *Ternary->getCond())); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: test/clang-tidy/readability-simplify-bool-expr.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-simplify-bool-expr.cpp @@ -0,0 +1,280 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-simplify-boolean-expr %t +// REQUIRES: shell + +bool a1 = false; + +//=-=-=-=-=-=-= operator == +bool aa = false == a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool aa = !a1;{{$}} +bool ab = true == a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool ab = a1;{{$}} +bool a2 = a1 == false; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a2 = !a1;{{$}} +bool a3 = a1 == true; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a3 = a1;{{$}} + +//=-=-=-=-=-=-= operator != +bool n1 = a1 != false; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool n1 = a1;{{$}} +bool n2 = a1 != true; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool n2 = !a1;{{$}} +bool n3 = false != a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool n3 = a1;{{$}} +bool n4 = true != a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool n4 = !a1;{{$}} + +//=-=-=-=-=-=-= operator || +bool a4 = a1 || false; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a4 = a1;{{$}} +bool a5 = a1 || true; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a5 = true;{{$}} +bool a6 = false || a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a6 = a1;{{$}} +bool a7 = true || a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a7 = true;{{$}} + +//=-=-=-=-=-=-= operator && +bool a8 = a1 && false; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// X-CHECK-FIXES: {{^}}bool a8 = false;{{$}} +bool a9 = a1 && true; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool a9 = a1;{{$}} +bool ac = false && a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool ac = false;{{$}} +bool ad = true && a1; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] +// CHECK-FIXES: {{^}}bool ad = a1;{{$}} + +void if_with_bool_literal_condition() +{ + int i = 0; + if (false) { + i = 1; + } else { + i = 2; + } + i = 3; + // CHECK-MESSAGES: :[[@LINE-6]]:9: warning: Redundant boolean constant in if statement condition. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}int i = 0;{{$}} + // CHECK-FIXES-NEXT: {{^ }}{{{$}} + // CHECK-FIXES-NEXT: {{^ }}i = 2;{{$}} + // CHECK-FIXES-NEXT: {{^ }}}{{$}} + // CHECK-FIXES-NEXT: {{^ }}i = 3;{{$}} + + i = 4; + if (true) { + i = 5; + } else { + i = 6; + } + i = 7; + // CHECK-MESSAGES: :[[@LINE-6]]:9: warning: Redundant boolean constant in if statement condition. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}i = 4;{{$}} + // CHECK-FIXES-NEXT: {{^ }}{{{$}} + // CHECK-FIXES-NEXT: {{^ }}i = 5;{{$}} + // CHECK-FIXES-NEXT: {{^ }}}{{$}} + // CHECK-FIXES-NEXT: {{^ }}i = 7;{{$}} + + i = 8; + if (false) { + i = 9; + } + i = 11; + // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: Redundant boolean constant in if statement condition. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}i = 8;{{$}} + // CHECK-FIXES-NEXT: {{^ $}} + // CHECK-FIXES-NEXT: {{^ }}i = 11;{{$}} +} + +void operator_equals() +{ + int i = 0; + bool b1 = (i > 2); + if (b1 == true) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (b1) {{{$}} + i = 5; + } else { + i = 6; + } + bool b2 = (i > 4); + if (b2 == false) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (!b2) {{{$}} + i = 7; + } else { + i = 9; + } + bool b3 = (i > 6); + if (true == b3) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (b3) {{{$}} + i = 10; + } else { + i = 11; + } + bool b4 = (i > 8); + if (false == b4) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (!b4) {{{$}} + i = 12; + } else { + i = 13; + } +} + +void operator_or() +{ + int i = 0; + bool b5 = (i > 10); + if (b5 || false) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (b5) {{{$}} + i = 14; + } else { + i = 15; + } + bool b6 = (i > 10); + if (b6 || true) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (true) {{{$}} + i = 16; + } else { + i = 17; + } + bool b7 = (i > 10); + if (false || b7) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // X-CHECK-FIXES: {{^ }}if (b4) {{{$}} + i = 18; + } else { + i = 19; + } + bool b8 = (i > 10); + if (true || b8) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // X-CHECK-FIXES: {{^ }}if (true) {{{$}} + i = 20; + } else { + i = 21; + } +} + +void operator_and() +{ + int i = 0; + bool b9 = (i > 20); + if (b9 && false) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (false) {{{$}} + i = 22; + } else { + i = 23; + } + bool ba = (i > 20); + if (ba && true) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (ba) {{{$}} + i = 24; + } else { + i = 25; + } + bool bb = (i > 20); + if (false && bb) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (false) {{{$}} + i = 26; + } else { + i = 27; + } + bool bc = (i > 20); + if (true && bc) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (bc) {{{$}} + i = 28; + } else { + i = 29; + } +} + +void ternary_operator() +{ + int i = 0; + bool bd = (i > 20) ? true : false; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: Redundant boolean literal in ternary expression result. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}bool bd = (i > 20);{{$}} + bool be = (i > 20) ? false : true; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: Redundant boolean literal in ternary expression result. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}bool be = !(i > 20);{{$}} +} + +void operator_not_equal() +{ + int i = 0; + bool bf = (i > 20); + if (false != bf) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (bf) {{{$}} + i = 30; + } else { + i = 31; + } + bool bg = (i > 20); + if (true != bg) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (!bg) {{{$}} + i = 32; + } else { + i = 33; + } + bool bh = (i > 20); + if (bh != false) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (bh) {{{$}} + i = 34; + } else { + i = 35; + } + bool bi = (i > 20); + if (bi != true) { + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-FIXES: {{^ }}if (!bi) {{{$}} + i = 36; + } else { + i = 37; + } +} + +void nested_booleans() +{ + if (false || (true || false)) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-XFIXES: {{^ }}if (false || (true)) {{{$}} + } + if (true && (true || false)) { + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-XFIXES: {{^ }}if (true && (true)) {{{$}} + } + if (false || (true && false)) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-XFIXES: {{^ }}if (false || (false)) {{{$}} + } + if (true && (true && false)) { + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: Redundant boolean constant supplied to boolean operator. [readability-simplify-boolean-expr] + // CHECK-XFIXES: {{^ }}if (true && (false)) {{{$}} + } +}