LegalizeAdulthood updated this revision to Diff 180184.
LegalizeAdulthood added a comment.
clang-format
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D56303/new/
https://reviews.llvm.org/D56303
Files:
clang-tidy/readability/SimplifyBooleanExprCheck.cpp
clang-tidy/readability/SimplifyBooleanExprCheck.h
test/clang-tidy/readability-simplify-bool-expr-case.cpp
Index: test/clang-tidy/readability-simplify-bool-expr-case.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/readability-simplify-bool-expr-case.cpp
@@ -0,0 +1,586 @@
+// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t
+
+bool switch_stmt(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ if (b == true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+
+ case 1:
+ if (b == false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(!b\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+
+ case 2:
+ if (b && true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+
+ case 3:
+ if (b && false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(false\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+
+ case 4:
+ if (b || true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(true\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ // CHECK-FIXES-NEXT: {{break;}}
+
+ case 5:
+ if (b || false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+
+ case 6:
+ return i > 0 ? true : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{return i > 0;}}
+
+ case 7:
+ return i > 0 ? false : true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{return i <= 0;}}
+
+ case 8:
+ if (true)
+ j = 10;
+ else
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{j = 10;$}}
+ // CHECK-FIXES-NEXT: {{break;$}}
+
+ case 9:
+ if (false)
+ j = -20;
+ else
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{j = 10;}}
+ // CHECK-FIXES-NEXT: {{break;}}
+
+ case 10:
+ if (j > 10)
+ return true;
+ else
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{return j > 10;}}
+
+ case 11:
+ if (j > 10)
+ return false;
+ else
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{return j <= 10;}}
+
+ case 12:
+ if (j > 10)
+ b = true;
+ else
+ b = false;
+ return b;
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{b = j > 10;}}
+ // CHECK-FIXES-NEXT: {{return b;}}
+
+ case 13:
+ if (j > 10)
+ b = false;
+ else
+ b = true;
+ return b;
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{b = j <= 10;}}
+ // CHECK-FIXES-NEXT: {{return b;}}
+
+ case 14:
+ if (j > 10)
+ return true;
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: {{.*}} in conditional return
+ // FIXES: {{return j > 10;}}
+
+ case 15:
+ if (j > 10)
+ return false;
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: {{.*}} in conditional return
+ // FIXES: {{return j <= 10;}}
+
+ case 16:
+ if (j > 10)
+ return true;
+ return true;
+ return false;
+
+ case 17:
+ if (j > 10)
+ return false;
+ return false;
+ return true;
+
+ case 100: {
+ if (b == true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ }
+
+ case 101: {
+ if (b == false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(!b\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+ }
+
+ case 102: {
+ if (b && true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ }
+
+ case 103: {
+ if (b && false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(false\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+ }
+
+ case 104: {
+ if (b || true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(true\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ // CHECK-FIXES-NEXT: {{break;}}
+ }
+
+ case 105: {
+ if (b || false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+ }
+
+ case 106: {
+ return i > 0 ? true : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{return i > 0;}}
+ }
+
+ case 107: {
+ return i > 0 ? false : true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{return i <= 0;}}
+ }
+
+ case 108: {
+ if (true)
+ j = 10;
+ else
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{j = 10;$}}
+ // CHECK-FIXES-NEXT: {{break;$}}
+ }
+
+ case 109: {
+ if (false)
+ j = -20;
+ else
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{j = 10;}}
+ // CHECK-FIXES-NEXT: {{break;}}
+ }
+
+ case 110: {
+ if (j > 10)
+ return true;
+ else
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{return j > 10;}}
+ }
+
+ case 111: {
+ if (j > 10)
+ return false;
+ else
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{return j <= 10;}}
+ }
+
+ case 112: {
+ if (j > 10)
+ b = true;
+ else
+ b = false;
+ return b;
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{b = j > 10;}}
+ // CHECK-FIXES-NEXT: {{return b;}}
+ }
+
+ case 113: {
+ if (j > 10)
+ b = false;
+ else
+ b = true;
+ return b;
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{b = j <= 10;}}
+ // CHECK-FIXES-NEXT: {{return b;}}
+ }
+
+ case 114: {
+ if (j > 10)
+ return true;
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: {{.*}} in conditional return
+ // CHECK-FIXES: {{return j > 10;}}
+ }
+
+ case 115: {
+ if (j > 10)
+ return false;
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: {{.*}} in conditional return
+ // CHECK-FIXES: {{return j <= 10;}}
+ }
+
+ case 116: {
+ return false;
+ if (j > 10)
+ return true;
+ }
+
+ case 117: {
+ return true;
+ if (j > 10)
+ return false;
+ }
+ }
+
+ return j > 0;
+}
+
+bool default_stmt0(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (b == true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ }
+ return false;
+}
+
+bool default_stmt1(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (b == false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(!b\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+ }
+ return false;
+}
+
+bool default_stmt2(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (b && true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ }
+ return false;
+}
+
+bool default_stmt3(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (b && false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(false\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+ }
+ return false;
+}
+
+bool default_stmt4(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (b || true)
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(true\)}}
+ // CHECK-FIXES-NEXT: {{j = 10;}}
+ // CHECK-FIXES-NEXT: {{break;}}
+ }
+ return false;
+}
+
+bool default_stmt5(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (b || false)
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{if \(b\)}}
+ // CHECK-FIXES-NEXT: {{j = -20;}}
+ }
+ return false;
+}
+
+bool default_stmt6(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ return i > 0 ? true : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{return i > 0;}}
+ }
+ return false;
+}
+
+bool default_stmt7(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ return i > 0 ? false : true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{return i <= 0;}}
+ }
+ return false;
+}
+
+bool default_stmt8(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (true)
+ j = 10;
+ else
+ j = -20;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{j = 10;$}}
+ // CHECK-FIXES-NEXT: {{break;$}}
+ }
+ return false;
+}
+
+bool default_stmt9(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (false)
+ j = -20;
+ else
+ j = 10;
+ break;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{j = 10;}}
+ // CHECK-FIXES-NEXT: {{break;}}
+ }
+ return false;
+}
+
+bool default_stmt10(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ return true;
+ else
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{return j > 10;}}
+ }
+ return false;
+}
+
+bool default_stmt11(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ return false;
+ else
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-3]]:14: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{return j <= 10;}}
+ }
+ return false;
+}
+
+bool default_stmt12(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ b = true;
+ else
+ b = false;
+ return b;
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{b = j > 10;}}
+ // CHECK-FIXES-NEXT: {{return b;}}
+ }
+ return false;
+}
+
+bool default_stmt13(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ b = false;
+ else
+ b = true;
+ return b;
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{b = j <= 10;}}
+ // CHECK-FIXES-NEXT: {{return b;}}
+ }
+ return false;
+}
+
+bool default_stmt14(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ return true;
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: {{.*}} in conditional return
+ // FIXES: {{return j > 10;}}
+ }
+ return false;
+}
+
+bool default_stmt15(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ return false;
+ return true;
+ // CHECK-MESSAGES: :[[@LINE-2]]:14: warning: {{.*}} in conditional return
+ // FIXES: {{return j <= 10;}}
+ }
+ return false;
+}
+
+bool default_stmt16(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return false;
+
+ default:
+ if (j > 10)
+ return true;
+ }
+ return false;
+}
+
+bool default_stmt17(int i, int j, bool b) {
+ switch (i) {
+ case 0:
+ return true;
+
+ default:
+ if (j > 10)
+ return false;
+ }
+ return false;
+}
Index: clang-tidy/readability/SimplifyBooleanExprCheck.h
===================================================================
--- clang-tidy/readability/SimplifyBooleanExprCheck.h
+++ clang-tidy/readability/SimplifyBooleanExprCheck.h
@@ -50,6 +50,12 @@
void matchCompoundIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
StringRef Id);
+ void matchCaseIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef Id);
+
+ void matchDefaultIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef Id);
+
void
replaceWithThenStatement(const ast_matchers::MatchFinder::MatchResult &Result,
const CXXBoolLiteralExpr *BoolLiteral);
@@ -60,20 +66,31 @@
void
replaceWithCondition(const ast_matchers::MatchFinder::MatchResult &Result,
- const ConditionalOperator *Ternary,
- bool Negated = false);
+ const ConditionalOperator *Ternary, bool Negated);
void replaceWithReturnCondition(
const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If,
- bool Negated = false);
+ bool Negated);
void
replaceWithAssignment(const ast_matchers::MatchFinder::MatchResult &Result,
- const IfStmt *If, bool Negated = false);
+ const IfStmt *If, bool Negated);
void replaceCompoundReturnWithCondition(
const ast_matchers::MatchFinder::MatchResult &Result,
- const CompoundStmt *Compound, bool Negated = false);
+ const CompoundStmt *Compound, bool Negated);
+
+ void replaceSwitchCaseCompoundReturnWithCondition(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Compound, bool Negated, const SwitchCase *SwitchCase);
+
+ void replaceCaseCompoundReturnWithCondition(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Compound, bool Negated);
+
+ void replaceDefaultCompoundReturnWithCondition(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Compound, bool Negated);
void issueDiag(const ast_matchers::MatchFinder::MatchResult &Result,
SourceLocation Loc, StringRef Description,
Index: clang-tidy/readability/SimplifyBooleanExprCheck.cpp
===================================================================
--- clang-tidy/readability/SimplifyBooleanExprCheck.cpp
+++ clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -47,8 +47,15 @@
const char IfAssignNotBoolId[] = "if-assign-not";
const char IfAssignObjId[] = "if-assign-obj";
const char CompoundReturnId[] = "compound-return";
+const char CompoundIfId[] = "compound-if";
const char CompoundBoolId[] = "compound-bool";
const char CompoundNotBoolId[] = "compound-bool-not";
+const char CaseId[] = "case";
+const char CaseCompoundBoolId[] = "case-compound-bool";
+const char CaseCompoundNotBoolId[] = "case-compound-bool-not";
+const char DefaultId[] = "default";
+const char DefaultCompoundBoolId[] = "default-compound-bool";
+const char DefaultCompoundNotBoolId[] = "default-compound-bool-not";
const char IfStmtId[] = "if";
@@ -319,7 +326,7 @@
} // namespace
class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
- public:
+public:
Visitor(SimplifyBooleanExprCheck *Check,
const MatchFinder::MatchResult &Result)
: Check(Check), Result(Result) {}
@@ -329,12 +336,11 @@
return true;
}
- private:
+private:
SimplifyBooleanExprCheck *Check;
const MatchFinder::MatchResult &Result;
};
-
SimplifyBooleanExprCheck::SimplifyBooleanExprCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
@@ -361,8 +367,8 @@
const auto *LHS = Op->getLHS()->IgnoreParenImpCasts();
const auto *RHS = Op->getRHS()->IgnoreParenImpCasts();
- const CXXBoolLiteralExpr *Bool = nullptr;
- const Expr *Other = nullptr;
+ const CXXBoolLiteralExpr *Bool;
+ const Expr *Other;
if ((Bool = dyn_cast<CXXBoolLiteralExpr>(LHS)))
Other = RHS;
else if ((Bool = dyn_cast<CXXBoolLiteralExpr>(RHS)))
@@ -377,46 +383,46 @@
if (!isa<CXXBoolLiteralExpr>(Other) && containsBoolLiteral(Other))
return;
- bool BoolValue = Bool->getValue();
+ const 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->getBeginLoc(), RHS->getEndLoc());
- issueDiag(Result, Bool->getBeginLoc(), SimplifyOperatorDiagnostic, Range,
- Replacement);
- };
+ const auto replaceWithExpression =
+ [this, &Result, LHS, RHS, Bool](const Expr *ReplaceWith, bool Negated) {
+ const std::string Replacement =
+ replacementExpression(Result, Negated, ReplaceWith);
+ SourceRange Range(LHS->getBeginLoc(), RHS->getEndLoc());
+ issueDiag(Result, Bool->getBeginLoc(), 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;
+ 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;
}
}
@@ -499,6 +505,42 @@
this);
}
+void SimplifyBooleanExprCheck::matchCaseIfReturnsBool(MatchFinder *Finder,
+ bool Value,
+ StringRef Id) {
+ // binding to the returnStmt matched is pointless because we can't guarantee
+ // anything about the ordering of the return statement and the case statement.
+ // If only we had a statement sequence matcher...
+ Finder->addMatcher(
+ switchStmt(
+ has(compoundStmt(
+ has(caseStmt(hasDescendant(ifStmt(hasThen(returnsBool(Value)),
+ unless(hasElse(stmt())))
+ .bind(CompoundIfId)))
+ .bind(CaseId)),
+ has(returnStmt(has(cxxBoolLiteral(equals(!Value))))))
+ .bind(Id))),
+ this);
+}
+
+void SimplifyBooleanExprCheck::matchDefaultIfReturnsBool(MatchFinder *Finder,
+ bool Value,
+ StringRef Id) {
+ // binding to the returnStmt matched is pointless because we can't guarantee
+ // anything about the ordering of the return statement and the case statement.
+ // If only we had a statement sequence matcher...
+ Finder->addMatcher(
+ switchStmt(has(
+ compoundStmt(
+ has(defaultStmt(hasDescendant(ifStmt(hasThen(returnsBool(Value)),
+ unless(hasElse(stmt())))
+ .bind(CompoundIfId)))
+ .bind(DefaultId)),
+ has(returnStmt(has(cxxBoolLiteral(equals(!Value))))))
+ .bind(Id))),
+ this);
+}
+
void SimplifyBooleanExprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "ChainedConditionalReturn", ChainedConditionalReturn);
Options.store(Opts, "ChainedConditionalAssignment",
@@ -522,6 +564,12 @@
matchCompoundIfReturnsBool(Finder, true, CompoundBoolId);
matchCompoundIfReturnsBool(Finder, false, CompoundNotBoolId);
+
+ matchCaseIfReturnsBool(Finder, true, CaseCompoundBoolId);
+ matchCaseIfReturnsBool(Finder, false, CaseCompoundNotBoolId);
+
+ matchDefaultIfReturnsBool(Finder, true, DefaultCompoundBoolId);
+ matchDefaultIfReturnsBool(Finder, false, DefaultCompoundNotBoolId);
}
void SimplifyBooleanExprCheck::check(const MatchFinder::MatchResult &Result) {
@@ -535,27 +583,41 @@
replaceWithElseStatement(Result, FalseConditionRemoved);
else if (const auto *Ternary =
Result.Nodes.getNodeAs<ConditionalOperator>(TernaryId))
- replaceWithCondition(Result, Ternary);
+ replaceWithCondition(Result, Ternary, false);
else if (const auto *TernaryNegated =
Result.Nodes.getNodeAs<ConditionalOperator>(TernaryNegatedId))
replaceWithCondition(Result, TernaryNegated, true);
else if (const auto *If = Result.Nodes.getNodeAs<IfStmt>(IfReturnsBoolId))
- replaceWithReturnCondition(Result, If);
+ replaceWithReturnCondition(Result, If, false);
else if (const auto *IfNot =
Result.Nodes.getNodeAs<IfStmt>(IfReturnsNotBoolId))
replaceWithReturnCondition(Result, IfNot, true);
else if (const auto *IfAssign =
Result.Nodes.getNodeAs<IfStmt>(IfAssignBoolId))
- replaceWithAssignment(Result, IfAssign);
+ replaceWithAssignment(Result, IfAssign, false);
else if (const auto *IfAssignNot =
Result.Nodes.getNodeAs<IfStmt>(IfAssignNotBoolId))
replaceWithAssignment(Result, IfAssignNot, true);
else if (const auto *Compound =
Result.Nodes.getNodeAs<CompoundStmt>(CompoundBoolId))
- replaceCompoundReturnWithCondition(Result, Compound);
- else if (const auto *Compound =
+ replaceCompoundReturnWithCondition(Result, Compound, false);
+ else if (const auto *CompoundNot =
Result.Nodes.getNodeAs<CompoundStmt>(CompoundNotBoolId))
- replaceCompoundReturnWithCondition(Result, Compound, true);
+ replaceCompoundReturnWithCondition(Result, CompoundNot, true);
+ else if (const auto *CaseCompound =
+ Result.Nodes.getNodeAs<CompoundStmt>(CaseCompoundBoolId))
+ replaceCaseCompoundReturnWithCondition(Result, CaseCompound, false);
+ else if (const auto *CaseCompoundNot =
+ Result.Nodes.getNodeAs<CompoundStmt>(CaseCompoundNotBoolId))
+ replaceCaseCompoundReturnWithCondition(Result, CaseCompoundNot, true);
+ else if (const auto *DefaultCompound =
+ Result.Nodes.getNodeAs<CompoundStmt>(DefaultCompoundBoolId))
+ replaceDefaultCompoundReturnWithCondition(Result, DefaultCompound, false);
+ else if (const auto *DefaultCompoundNot =
+ Result.Nodes.getNodeAs<CompoundStmt>(DefaultCompoundNotBoolId))
+ replaceDefaultCompoundReturnWithCondition(Result, DefaultCompoundNot, true);
+ else if (const auto TU = Result.Nodes.getNodeAs<Decl>("top"))
+ Visitor(this, Result).TraverseDecl(const_cast<Decl *>(TU));
}
void SimplifyBooleanExprCheck::issueDiag(
@@ -635,7 +697,7 @@
continue;
const Expr *Condition = If->getCond();
- std::string Replacement =
+ const std::string Replacement =
"return " + replacementExpression(Result, Negated, Condition);
issueDiag(
Result, Lit->getBeginLoc(), SimplifyConditionalReturnDiagnostic,
@@ -651,6 +713,87 @@
}
}
+void SimplifyBooleanExprCheck::replaceSwitchCaseCompoundReturnWithCondition(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *Compound,
+ bool Negated, const SwitchCase *SwitchCase) {
+ assert(SwitchCase != nullptr);
+
+ // The body shouldn't be empty because the matcher ensures that it must
+ // contain at least two statements:
+ // 1) A `return` statement returning a boolean literal `false` or `true`
+ // 2) An `if` statement with no `else` clause that consists of a single
+ // `return` statement returning the opposite boolean literal `true` or
+ // `false`.
+ assert(Compound->size() >= 2);
+
+ // We're looking for something like:
+ //
+ // switch (expr) {
+ // case 10:
+ // if (cond) return false;
+ // return true;
+ // }
+ //
+ // The matcher ensures that the case/if combination is already there,
+ // and that there is a return statement of this form somewhere in the
+ // compound statement associated with the switch contains a return
+ // statement of this form, but the return statement could be anywhere
+ // within the compound statement, so we have to manually check to see
+ // if the next statement after the if contains a return statement of
+ // the correct form. Ideally we'd be able to express this with the
+ // matchers, but that is currently impossible.
+ //
+ const auto *If = dyn_cast<IfStmt>(SwitchCase->getSubStmt());
+ assert(If != nullptr);
+ const CXXBoolLiteralExpr *Lit = stmtReturnsBool(If, Negated);
+ assert(Lit != nullptr);
+
+ // Advance to the matched CaseStmt
+ CompoundStmt::const_body_iterator Current = Compound->body_begin();
+ while (Current != Compound->body_end() && *Current != SwitchCase)
+ ++Current;
+ assert(Current != Compound->body_end());
+
+ // Advance to the next statement, watch out for something like:
+ //
+ // switch (expr) {
+ // case 0:
+ // return true;
+ //
+ // case 1:
+ // if (cond) return false;
+ // }
+ //
+ ++Current;
+ if (Current == Compound->body_end())
+ return;
+
+ if (const auto *Ret = dyn_cast<ReturnStmt>(*Current)) {
+ if (stmtReturnsBool(Ret, !Negated)) {
+ const Expr *Condition = If->getCond();
+ const std::string Replacement =
+ "return " + replacementExpression(Result, Negated, Condition);
+ issueDiag(Result, Lit->getBeginLoc(), SimplifyConditionalReturnDiagnostic,
+ SourceRange(If->getBeginLoc(), Ret->getEndLoc()), Replacement);
+ }
+ }
+}
+
+void SimplifyBooleanExprCheck::replaceCaseCompoundReturnWithCondition(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *Compound,
+ bool Negated) {
+ replaceSwitchCaseCompoundReturnWithCondition(
+ Result, Compound, Negated, Result.Nodes.getNodeAs<CaseStmt>(CaseId));
+}
+
+void SimplifyBooleanExprCheck::replaceDefaultCompoundReturnWithCondition(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *Compound,
+ bool Negated) {
+ replaceSwitchCaseCompoundReturnWithCondition(
+ Result, Compound, Negated,
+ Result.Nodes.getNodeAs<DefaultStmt>(DefaultId));
+}
+
void SimplifyBooleanExprCheck::replaceWithAssignment(
const MatchFinder::MatchResult &Result, const IfStmt *IfAssign,
bool Negated) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits