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();
/* ItlookstheclangSema::LookupOverloadedOperatorNameisthechunkoffunctionalityIneed, butIhavenoideahowtocallitfromhere. Actuallyfindingtherightstandardlibraryoperatorsrequiresdoingconversionsandotherfunkystuff. Fornow,justassumethatstandardlibraryoperatorsarewell-behaved,andhavenegatedoperators.
*/ 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()) returnfalse;
foundFunction = findMemberOperator(baseCXXRecordDecl, ooOpcode, rhsRecordDecl); returnfalse;
};
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;
}
enumclass 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 SimplifyBool::run() { if (compiler.getLangOpts().CPlusPlus) {
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
}
}
bool SimplifyBool::VisitUnaryOperator(UnaryOperator const * expr) { if (expr->getOpcode() != UO_LNot) { returntrue;
} if (ignoreLocation(expr)) { returntrue;
} auto e = getSubExprOfLogicalNegation(expr->getSubExpr()); if (e) { // Ignore macros, otherwise // OSL_ENSURE(!b, ...); // triggers. if (e->getBeginLoc().isMacroID()) returntrue; // double logical not of an int is an idiom to convert to bool autoconst sub = ignoreAllImplicit(e); if (!sub->getType()->isBooleanType()) returntrue;
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(); returntrue;
} auto sub = expr->getSubExpr()->IgnoreParenImpCasts(); auto reversed = false; if (autoconst rewritten = dyn_cast<CXXRewrittenBinaryOperator>(sub)) { if (rewritten->isReversed()) { if (rewritten->getOperator() == BO_EQ) { autoconst sem = rewritten->getSemanticForm(); bool match; if (autoconst op1 = dyn_cast<BinaryOperator>(sem)) {
match = op1->getOpcode() == BO_EQ;
} elseif (autoconst 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()) returntrue; if (binaryOp->isComparisonOp())
{ auto t = binaryOp->getLHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType(); if (t->isTemplateTypeParmType() || t->isDependentType() || t->isRecordType()) returntrue; // for floating point (with NaN) !(x<y) need not be equivalent to x>=y if (t->isFloatingType() ||
binaryOp->getRHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType()->isFloatingType()) returntrue;
report(
DiagnosticsEngine::Warning,
("logical negation of comparison operator, can be simplified by inverting operator"),
expr->getBeginLoc())
<< expr->getSourceRange();
} elseif (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()) returntrue; 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)) returntrue;
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(); autoconst negOp = findOperator(compiler, negatedOpcode, lhs, rhs); if (!negOp) returntrue; // 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) returntrue;
} // QA code
StringRef fn(handler.getMainFileName()); if (loplugin::isSamePathname(fn, SRCDIR "/testtools/source/bridgetest/bridgetest.cxx")) returntrue;
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();
} returntrue;
}
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: returntrue;
}
}
bool SimplifyBool::visitBinLT(BinaryOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
&& expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
{ returntrue;
} 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;
} returntrue;
}
bool SimplifyBool::visitBinGT(BinaryOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
&& expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
{ returntrue;
} 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;
} returntrue;
}
bool SimplifyBool::visitBinLE(BinaryOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
&& expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
{ returntrue;
} 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;
} returntrue;
}
bool SimplifyBool::visitBinGE(BinaryOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
&& expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
{ returntrue;
} 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;
} returntrue;
}
bool SimplifyBool::visitBinEQ(BinaryOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
&& expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
{ returntrue;
} 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;
} returntrue;
}
bool SimplifyBool::visitBinNE(BinaryOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
&& expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
{ returntrue;
} 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;
} returntrue;
}
bool SimplifyBool::VisitConditionalOperator(ConditionalOperator const * expr) { if (ignoreLocation(expr)) { returntrue;
} 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;
} returntrue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.