summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/store/simplifybool.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/store/simplifybool.cxx')
-rw-r--r--compilerplugins/clang/store/simplifybool.cxx1333
1 files changed, 1333 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/simplifybool.cxx b/compilerplugins/clang/store/simplifybool.cxx
new file mode 100644
index 000000000..973ab6a7a
--- /dev/null
+++ b/compilerplugins/clang/store/simplifybool.cxx
@@ -0,0 +1,1333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cassert>
+
+#include "plugin.hxx"
+#include "clang/AST/CXXInheritance.h"
+
+namespace {
+
+// Like clang::Stmt::IgnoreImplicit (lib/AST/Stmt.cpp), but also looking through implicit
+// UserDefinedConversion's member function call:
+Expr const * ignoreAllImplicit(Expr const * expr) {
+ if (auto const e = dyn_cast<ExprWithCleanups>(expr)) {
+ expr = e->getSubExpr();
+ }
+ if (auto const e = dyn_cast<MaterializeTemporaryExpr>(expr)) {
+ expr = e->getSubExpr();
+ }
+ if (auto const e = dyn_cast<CXXBindTemporaryExpr>(expr)) {
+ expr = e->getSubExpr();
+ }
+ while (auto const e = dyn_cast<ImplicitCastExpr>(expr)) {
+ expr = e->getSubExpr();
+ if (e->getCastKind() == CK_UserDefinedConversion) {
+ auto const ce = cast<CXXMemberCallExpr>(expr);
+ assert(ce->getNumArgs() == 0);
+ expr = ce->getImplicitObjectArgument();
+ }
+ }
+ return expr;
+}
+
+Expr const * ignoreParenImpCastAndComma(Expr const * expr) {
+ for (;;) {
+ expr = expr->IgnoreParenImpCasts();
+ auto e = dyn_cast<BinaryOperator>(expr);
+ if (e == nullptr || e->getOpcode() != BO_Comma) {
+ return expr;
+ }
+ expr = e->getRHS();
+ }
+}
+
+Expr const * getSubExprOfLogicalNegation(Expr const * expr) {
+ auto e = dyn_cast<UnaryOperator>(ignoreParenImpCastAndComma(expr));
+ return e == nullptr || e->getOpcode() != UO_LNot
+ ? nullptr : e->getSubExpr();
+}
+
+clang::Type const * stripConstRef(clang::Type const * type) {
+ auto lvalueType = dyn_cast<LValueReferenceType>(type);
+ if (!lvalueType)
+ return type;
+ return lvalueType->getPointeeType()->getUnqualifiedDesugaredType();
+}
+
+bool isCompatibleTypeForOperator(clang::Type const * paramType, CXXRecordDecl const * argRecordDecl) {
+ paramType = stripConstRef(paramType);
+ auto paramRecordType = dyn_cast<RecordType>(paramType);
+ if (!paramRecordType)
+ return false;
+ CXXRecordDecl const * paramRecordDecl = dyn_cast<CXXRecordDecl>(paramRecordType->getDecl());
+ if (!paramRecordDecl)
+ return false;
+ return argRecordDecl == paramRecordDecl || argRecordDecl->isDerivedFrom(paramRecordDecl);
+}
+
+FunctionDecl const * findMemberOperator(CXXRecordDecl const * recordDecl, OverloadedOperatorKind ooOpcode, CXXRecordDecl const * rhs) {
+ for (auto it = recordDecl->method_begin(); it != recordDecl->method_end(); ++it) {
+ if (it->getOverloadedOperator() == ooOpcode) {
+ if (it->getNumParams() == 1 && isCompatibleTypeForOperator(it->getParamDecl(0)->getType().getTypePtr(), rhs))
+ return *it;
+ }
+ }
+ return nullptr;
+}
+
+// Magic value to indicate we assume this operator exists
+static FunctionDecl const * const ASSUME_OPERATOR_EXISTS = reinterpret_cast<FunctionDecl const *>(-1);
+
+// Search for an operator with matching parameter types; while this may miss some operators with
+// odd parameter types that would actually be used by the compiler, it is overall better to have too
+// many false negatives (i.e., miss valid loplugin:simplifybool warnings) than false positives here:
+FunctionDecl const * findOperator(CompilerInstance& compiler, BinaryOperator::Opcode opcode, clang::Type const * lhsType, clang::Type const * rhsType) {
+ auto lhsRecordType = dyn_cast<RecordType>(lhsType);
+ if (!lhsRecordType)
+ return nullptr;
+ auto rhsRecordType = dyn_cast<RecordType>(rhsType);
+ if (!rhsRecordType)
+ return nullptr;
+ CXXRecordDecl const * lhsRecordDecl = dyn_cast<CXXRecordDecl>(lhsRecordType->getDecl());
+ if (!lhsRecordDecl)
+ return nullptr;
+ CXXRecordDecl const * rhsRecordDecl = dyn_cast<CXXRecordDecl>(rhsRecordType->getDecl());
+ if (!rhsRecordDecl)
+ return nullptr;
+
+ auto ctx = lhsRecordDecl->getCanonicalDecl()->getDeclContext();
+
+ /*
+ It looks the clang Sema::LookupOverloadedOperatorName is the chunk of functionality I need,
+ but I have no idea how to call it from here.
+ Actually finding the right standard library operators requires doing conversions and other funky stuff.
+ For now, just assume that standard library operators are well-behaved, and have negated operators.
+ */
+ if (ctx->isStdNamespace())
+ return ASSUME_OPERATOR_EXISTS;
+ if (auto namespaceDecl = dyn_cast<NamespaceDecl>(ctx)) {
+ // because, of course, half the standard library is not "in the standard namespace"
+ if (namespaceDecl->getName() == "__gnu_debug")
+ return ASSUME_OPERATOR_EXISTS;
+ }
+
+ // search for member overloads
+ // (using the hard way here because DeclContext::lookup does not work for member operators)
+ auto ooOpcode = BinaryOperator::getOverloadedOperator(opcode);
+ FunctionDecl const * foundFunction = findMemberOperator(lhsRecordDecl, ooOpcode, rhsRecordDecl);
+ if (foundFunction)
+ return foundFunction;
+ auto ForallBasesCallback = [&](const CXXRecordDecl *baseCXXRecordDecl)
+ {
+ if (baseCXXRecordDecl->isInvalidDecl())
+ return false;
+ foundFunction = findMemberOperator(baseCXXRecordDecl, ooOpcode, rhsRecordDecl);
+ return false;
+ };
+
+ lhsRecordDecl->forallBases(ForallBasesCallback);
+ if (foundFunction)
+ return foundFunction;
+
+ // search for free function overloads
+ if (ctx->getDeclKind() == Decl::LinkageSpec) {
+ ctx = ctx->getParent();
+ }
+ auto operatorDeclName = compiler.getASTContext().DeclarationNames.getCXXOperatorName(ooOpcode);
+ auto res = ctx->lookup(operatorDeclName);
+ for (auto d = res.begin(); d != res.end(); ++d) {
+ FunctionDecl const * f = dyn_cast<FunctionDecl>(*d);
+ if (!f || f->getNumParams() != 2)
+ continue;
+ if (!isCompatibleTypeForOperator(f->getParamDecl(0)->getType().getTypePtr(), lhsRecordDecl))
+ continue;
+ if (!isCompatibleTypeForOperator(f->getParamDecl(1)->getType().getTypePtr(), rhsRecordDecl))
+ continue;
+ return f;
+ }
+ return nullptr;
+}
+
+enum class Value { Unknown, False, True };
+
+Value getValue(Expr const * expr) {
+ expr = ignoreParenImpCastAndComma(expr);
+ if (expr->getType()->isBooleanType()) {
+ // Instead going via Expr::isCXX11ConstantExpr would turn up exactly one
+ // additional place in svx/source/dialog/framelinkarray.cxx
+ //
+ // const bool DIAG_DBL_CLIP_DEFAULT = false;
+ // ...
+ // ... = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
+ //
+ // where it is unclear whether it is not actually better to consider
+ // DIAG_DBL_CLIP_DEFAULT a tunable parameter (and thus not to simplify):
+ auto lit = dyn_cast<CXXBoolLiteralExpr>(expr);
+ if (lit != nullptr) {
+ return lit->getValue() ? Value::True : Value::False;
+ }
+ }
+ return Value::Unknown;
+}
+
+class SimplifyBool:
+ public loplugin::FilteringPlugin<SimplifyBool>
+{
+public:
+ explicit SimplifyBool(loplugin::InstantiationData const & data):
+ FilteringPlugin(data) {}
+
+ void run() override;
+
+ bool VisitUnaryOperator(UnaryOperator const * expr);
+
+ bool VisitBinaryOperator(BinaryOperator const * expr);
+
+ bool VisitConditionalOperator(ConditionalOperator const * expr);
+
+ bool TraverseFunctionDecl(FunctionDecl *);
+
+ bool TraverseCXXMethodDecl(CXXMethodDecl *);
+
+private:
+ bool visitBinLT(BinaryOperator const * expr);
+
+ bool visitBinGT(BinaryOperator const * expr);
+
+ bool visitBinLE(BinaryOperator const * expr);
+
+ bool visitBinGE(BinaryOperator const * expr);
+
+ bool visitBinEQ(BinaryOperator const * expr);
+
+ bool visitBinNE(BinaryOperator const * expr);
+
+ FunctionDecl* m_insideFunctionDecl = nullptr;
+};
+
+void SimplifyBool::run() {
+ if (compiler.getLangOpts().CPlusPlus) {
+ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+ }
+}
+
+bool SimplifyBool::VisitUnaryOperator(UnaryOperator const * expr) {
+ if (expr->getOpcode() != UO_LNot) {
+ return true;
+ }
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ auto e = getSubExprOfLogicalNegation(expr->getSubExpr());
+ if (e) {
+ // Ignore macros, otherwise
+ // OSL_ENSURE(!b, ...);
+ // triggers.
+ if (e->getBeginLoc().isMacroID())
+ return true;
+ // double logical not of an int is an idiom to convert to bool
+ auto const sub = ignoreAllImplicit(e);
+ if (!sub->getType()->isBooleanType())
+ return true;
+ report(
+ DiagnosticsEngine::Warning,
+ ("double logical negation expression of the form '!!A' (with A of type"
+ " %0) can %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << sub->getType()
+ << sub->getType()->isBooleanType()
+ << expr->getSourceRange();
+ return true;
+ }
+ auto sub = expr->getSubExpr()->IgnoreParenImpCasts();
+ auto reversed = false;
+ if (auto const rewritten = dyn_cast<CXXRewrittenBinaryOperator>(sub)) {
+ if (rewritten->isReversed()) {
+ if (rewritten->getOperator() == BO_EQ) {
+ auto const sem = rewritten->getSemanticForm();
+ bool match;
+ if (auto const op1 = dyn_cast<BinaryOperator>(sem)) {
+ match = op1->getOpcode() == BO_EQ;
+ } else if (auto const op2 = dyn_cast<CXXOperatorCallExpr>(sem)) {
+ match = op2->getOperator() == OO_EqualEqual;
+ } else {
+ match = false;
+ }
+ if (match) {
+ sub = sem;
+ reversed = true;
+ }
+ }
+ }
+ }
+ if (auto binaryOp = dyn_cast<BinaryOperator>(sub)) {
+ // Ignore macros, otherwise
+ // OSL_ENSURE(!b, ...);
+ // triggers.
+ if (binaryOp->getBeginLoc().isMacroID())
+ return true;
+ if (binaryOp->isComparisonOp())
+ {
+ auto t = binaryOp->getLHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
+ if (t->isTemplateTypeParmType() || t->isDependentType() || t->isRecordType())
+ return true;
+ // for floating point (with NaN) !(x<y) need not be equivalent to x>=y
+ if (t->isFloatingType() ||
+ binaryOp->getRHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType()->isFloatingType())
+ return true;
+ report(
+ DiagnosticsEngine::Warning,
+ ("logical negation of comparison operator, can be simplified by inverting operator"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ }
+ else if (binaryOp->isLogicalOp())
+ {
+ // if we find a negation condition inside, it is definitely better
+ // to expand it out
+ bool foundLNot = false;
+ auto containsNegationOrComparison = [&](Expr const * expr) {
+ expr = ignoreParenImpCastAndComma(expr);
+ if (auto unaryOp = dyn_cast<UnaryOperator>(expr))
+ if (unaryOp->getOpcode() == UO_LNot)
+ {
+ foundLNot = true;
+ return expr;
+ }
+ if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
+ if (binaryOp->isComparisonOp())
+ return expr;
+ if (auto cxxOpCall = dyn_cast<CXXOperatorCallExpr>(expr))
+ if (cxxOpCall->isComparisonOp())
+ return expr;
+ return (Expr const*)nullptr;
+ };
+ auto lhs = containsNegationOrComparison(binaryOp->getLHS());
+ auto rhs = containsNegationOrComparison(binaryOp->getRHS());
+ if (foundLNot || (lhs && rhs))
+ report(
+ DiagnosticsEngine::Warning,
+ ("logical negation of logical op containing negation, can be simplified"),
+ binaryOp->getBeginLoc())
+ << binaryOp->getSourceRange();
+ }
+ }
+ if (auto binaryOp = dyn_cast<CXXOperatorCallExpr>(sub)) {
+ // Ignore macros, otherwise
+ // OSL_ENSURE(!b, ...);
+ // triggers.
+ if (binaryOp->getBeginLoc().isMacroID())
+ return true;
+ auto op = binaryOp->getOperator();
+ // Negating things like > and >= would probably not be wise, there is no guarantee the negation holds for operator overloaded types.
+ // However, == and != are normally considered ok.
+ if (!(op == OO_EqualEqual || op == OO_ExclaimEqual))
+ return true;
+ BinaryOperator::Opcode negatedOpcode = BinaryOperator::negateComparisonOp(BinaryOperator::getOverloadedOpcode(op));
+ auto lhs = binaryOp->getArg(reversed ? 1 : 0)->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
+ auto rhs = binaryOp->getArg(reversed ? 0 : 1)->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
+ auto const negOp = findOperator(compiler, negatedOpcode, lhs, rhs);
+ if (!negOp)
+ return true;
+ // if we are inside a similar operator, ignore, eg. operator!= is often defined by calling !operator==
+ if (m_insideFunctionDecl && m_insideFunctionDecl->getNumParams() >= 1) {
+ auto t = stripConstRef(m_insideFunctionDecl->getParamDecl(0)->getType().getTypePtr());
+ if (t == lhs)
+ return true;
+ }
+ // QA code
+ StringRef fn(handler.getMainFileName());
+ if (loplugin::isSamePathname(fn, SRCDIR "/testtools/source/bridgetest/bridgetest.cxx"))
+ return true;
+ report(
+ DiagnosticsEngine::Warning,
+ ("logical negation of comparison operator, can be simplified by inverting operator"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ if (negOp != ASSUME_OPERATOR_EXISTS)
+ report(
+ DiagnosticsEngine::Note, "the presumed corresponding negated operator for %0 and %1 is declared here",
+ negOp->getLocation())
+ << binaryOp->getArg(reversed ? 1 : 0)->IgnoreImpCasts()->getType()
+ << binaryOp->getArg(reversed ? 0 : 1)->IgnoreImpCasts()->getType()
+ << negOp->getSourceRange();
+ }
+ return true;
+}
+
+bool SimplifyBool::VisitBinaryOperator(BinaryOperator const * expr) {
+ switch (expr->getOpcode()) {
+ case BO_LT:
+ return visitBinLT(expr);
+ case BO_GT:
+ return visitBinGT(expr);
+ case BO_LE:
+ return visitBinLE(expr);
+ case BO_GE:
+ return visitBinGE(expr);
+ case BO_EQ:
+ return visitBinEQ(expr);
+ case BO_NE:
+ return visitBinNE(expr);
+ default:
+ return true;
+ }
+}
+
+bool SimplifyBool::visitBinLT(BinaryOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
+ {
+ return true;
+ }
+ auto v1 = getValue(expr->getLHS());
+ auto v2 = getValue(expr->getRHS());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'A < false' (with A of type"
+ " %0) can logically be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getLHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'A < true' (with A"
+ " of type %0) can %select{logically|literally}1 be"
+ " simplified as '!A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << (expr->getLHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form '!A < true' (with A"
+ " of type %0) can %select{logically|literally}1 be"
+ " simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'false < A' (with A of type"
+ " %0) can %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'false < false' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'false < true' can"
+ " literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'true < A' (with A of type"
+ " %0) can logically be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'true < false' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than expression of the form 'true < true' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::visitBinGT(BinaryOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
+ {
+ return true;
+ }
+ auto v1 = getValue(expr->getLHS());
+ auto v2 = getValue(expr->getRHS());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'A > false' (with A of"
+ " type %0) can %select{logically|literally}1 be simplified as"
+ " 'A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'A > true' (with A of"
+ " type %0) can logically be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'false > A' (with A of"
+ " type %0) can logically be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'false > false' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'false > true' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getRHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'true > A' (with"
+ " A of type %0) can %select{logically|literally}1 be"
+ " simplified as '!A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << (expr->getRHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'true > !A' (with"
+ " A of type %0) can %select{logically|literally}1 be"
+ " simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'true > false' can"
+ " literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than expression of the form 'true > true' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::visitBinLE(BinaryOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
+ {
+ return true;
+ }
+ auto v1 = getValue(expr->getLHS());
+ auto v2 = getValue(expr->getRHS());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getLHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'A <="
+ " false' (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as"
+ " '!A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << (expr->getLHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form '!A <="
+ " false' (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'A <= true'"
+ " (with A of type %0) can logically be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'false <= A'"
+ " (with A of type %0) can logically be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'false <= false'"
+ " can literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'false <= true'"
+ " can literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'true <= A'"
+ " (with A of type %0) can %select{logically|literally}1 be"
+ " simplified as 'A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'true <= false'"
+ " can literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("less-than-or-equal-to expression of the form 'true <= true'"
+ " can literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::visitBinGE(BinaryOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
+ {
+ return true;
+ }
+ auto v1 = getValue(expr->getLHS());
+ auto v2 = getValue(expr->getRHS());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'A >= false'"
+ " (with A of type %0) can logically be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'A >= true'"
+ " (with A of type %0) can %select{logically|literally}1 be"
+ " simplified as 'A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getRHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form"
+ " 'false >= A' (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as"
+ " '!A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << (expr->getRHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form"
+ " 'false >= !A' (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'false >="
+ " false' can literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'false >="
+ " true' can literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'true >= A'"
+ " (with A of type %0) can logically be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'true >="
+ " false' can literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("greater-than-or-equal-to expression of the form 'true >="
+ " true' can literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::visitBinEQ(BinaryOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
+ {
+ return true;
+ }
+ auto v1 = getValue(expr->getLHS());
+ auto v2 = getValue(expr->getRHS());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getLHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'A == false' (with A"
+ " of type %0) can %select{logically|literally}1 be"
+ " simplified as '!A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << (expr->getLHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form '!A == false' (with A"
+ " of type %0) can %select{logically|literally}1 be"
+ " simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'A == true' (with A of type"
+ " %0) can %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getRHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'false == A' (with A"
+ " of type %0) can %select{logically|literally}1 be"
+ " simplified as '!A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << (expr->getRHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'false == !A' (with A"
+ " of type %0) can %select{logically|literally}1 be"
+ " simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'false == false' can"
+ " literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'false == true' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'true == A' (with A of type"
+ " %0) can %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'true == false' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("equal-to expression of the form 'true == true' can"
+ " literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::visitBinNE(BinaryOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
+ {
+ return true;
+ }
+ auto v1 = getValue(expr->getLHS());
+ auto v2 = getValue(expr->getRHS());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'A != false' (with A of"
+ " type %0) can %select{logically|literally}1 be simplified as"
+ " 'A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getLHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'A != true' (with"
+ " A of type %0) can %select{logically|literally}1 be"
+ " simplified as '!A'"),
+ expr->getBeginLoc())
+ << expr->getLHS()->IgnoreImpCasts()->getType()
+ << (expr->getLHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form '!A != true'"
+ " (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'false != A' (with A of"
+ " type %0) can %select{logically|literally}1 be simplified as"
+ " 'A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'false != false' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'false != true' can"
+ " literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getRHS());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'true != A' (with"
+ " A of type %0) can %select{logically|literally}1 be"
+ " simplified as '!A'"),
+ expr->getBeginLoc())
+ << expr->getRHS()->IgnoreImpCasts()->getType()
+ << (expr->getRHS()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'true != !A'"
+ " (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'true != false' can"
+ " literally be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("not-equal-to expression of the form 'true != true' can"
+ " literally be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::VisitConditionalOperator(ConditionalOperator const * expr) {
+ if (ignoreLocation(expr)) {
+ return true;
+ }
+ auto v1 = getValue(expr->getTrueExpr());
+ auto v2 = getValue(expr->getFalseExpr());
+ switch (v1) {
+ case Value::Unknown:
+ switch (v2) {
+ case Value::Unknown:
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? B : false' (with A of"
+ " type %0 and B of type %1) can %select{logically|literally}2"
+ " be simplified as 'A && B'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getTrueExpr()->IgnoreImpCasts()->getType()
+ << ((expr->getCond()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ && (expr->getTrueExpr()->IgnoreImpCasts()->getType()
+ ->isBooleanType()))
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getCond());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? B : true'"
+ " (with A of type %0 and B of type %1) can"
+ " %select{logically|literally}2 be simplified as '!A"
+ " || B'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getTrueExpr()->IgnoreImpCasts()->getType()
+ << ((expr->getCond()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ && (expr->getTrueExpr()->IgnoreImpCasts()->getType()
+ ->isBooleanType()))
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form '!A ? B : true'"
+ " (with A of type %0 and B of type %1) can"
+ " %select{logically|literally}2 be simplified as 'A ||"
+ " B'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << expr->getTrueExpr()->IgnoreImpCasts()->getType()
+ << (e->IgnoreImpCasts()->getType()->isBooleanType()
+ && (expr->getTrueExpr()->IgnoreImpCasts()
+ ->getType()->isBooleanType()))
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ }
+ break;
+ case Value::False:
+ switch (v2) {
+ case Value::Unknown:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getCond());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? false : B'"
+ " (with A of type %0 and B of type %1) can"
+ " %select{logically|literally}2 be simplified as '!A"
+ " && B'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getFalseExpr()->IgnoreImpCasts()->getType()
+ << ((expr->getCond()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ && (expr->getFalseExpr()->IgnoreImpCasts()
+ ->getType()->isBooleanType()))
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form '!A ? false : B'"
+ " (with A of type %0 and B of type %1) can"
+ " %select{logically|literally}2 be simplified as 'A &&"
+ " B'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << expr->getFalseExpr()->IgnoreImpCasts()->getType()
+ << (e->IgnoreImpCasts()->getType()->isBooleanType()
+ && (expr->getFalseExpr()->IgnoreImpCasts()
+ ->getType()->isBooleanType()))
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? false : false' (with"
+ " A of type %0) can logically be simplified as 'false'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ {
+ auto e = getSubExprOfLogicalNegation(expr->getCond());
+ if (e == nullptr) {
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? false : true'"
+ " (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as"
+ " '!A'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << (expr->getCond()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ << expr->getSourceRange();
+ } else {
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form '!A ? false :"
+ " true' (with A of type %0) can"
+ " %select{logically|literally}1 be simplified as 'A'"),
+ expr->getBeginLoc())
+ << e->IgnoreImpCasts()->getType()
+ << e->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ }
+ break;
+ }
+ }
+ break;
+ case Value::True:
+ switch (v2) {
+ case Value::Unknown:
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? true : B' (with A of"
+ " type %0 and B of type %1) can %select{logically|literally}2"
+ " be simplified as 'A || B'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getFalseExpr()->IgnoreImpCasts()->getType()
+ << ((expr->getCond()->IgnoreImpCasts()->getType()
+ ->isBooleanType())
+ && (expr->getFalseExpr()->IgnoreImpCasts()->getType()
+ ->isBooleanType()))
+ << expr->getSourceRange();
+ break;
+ case Value::False:
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? true : false' (with A"
+ " of type %0) can %select{logically|literally}1 be simplified"
+ " as 'A'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getCond()->IgnoreImpCasts()->getType()->isBooleanType()
+ << expr->getSourceRange();
+ break;
+ case Value::True:
+ report(
+ DiagnosticsEngine::Warning,
+ ("conditional expression of the form 'A ? true : true' (with A"
+ " of type %0) can logically be simplified as 'true'"),
+ expr->getBeginLoc())
+ << expr->getCond()->IgnoreImpCasts()->getType()
+ << expr->getSourceRange();
+ break;
+ }
+ break;
+ }
+ return true;
+}
+
+bool SimplifyBool::TraverseFunctionDecl(FunctionDecl * functionDecl) {
+ auto copy = m_insideFunctionDecl;
+ m_insideFunctionDecl = functionDecl;
+ bool ret = RecursiveASTVisitor::TraverseFunctionDecl(functionDecl);
+ m_insideFunctionDecl = copy;
+ return ret;
+}
+
+bool SimplifyBool::TraverseCXXMethodDecl(CXXMethodDecl * functionDecl) {
+ auto copy = m_insideFunctionDecl;
+ m_insideFunctionDecl = functionDecl;
+ bool ret = RecursiveASTVisitor::TraverseCXXMethodDecl(functionDecl);
+ m_insideFunctionDecl = copy;
+ return ret;
+}
+
+loplugin::Plugin::Registration<SimplifyBool> X("simplifybool");
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */