Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / compilerplugins / clang / store / simplifybool.cxx
blob973ab6a7a46472cb08ac437c0dd0316b4613c091
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <cassert>
12 #include "plugin.hxx"
13 #include "clang/AST/CXXInheritance.h"
15 namespace {
17 // Like clang::Stmt::IgnoreImplicit (lib/AST/Stmt.cpp), but also looking through implicit
18 // UserDefinedConversion's member function call:
19 Expr const * ignoreAllImplicit(Expr const * expr) {
20 if (auto const e = dyn_cast<ExprWithCleanups>(expr)) {
21 expr = e->getSubExpr();
23 if (auto const e = dyn_cast<MaterializeTemporaryExpr>(expr)) {
24 expr = e->getSubExpr();
26 if (auto const e = dyn_cast<CXXBindTemporaryExpr>(expr)) {
27 expr = e->getSubExpr();
29 while (auto const e = dyn_cast<ImplicitCastExpr>(expr)) {
30 expr = e->getSubExpr();
31 if (e->getCastKind() == CK_UserDefinedConversion) {
32 auto const ce = cast<CXXMemberCallExpr>(expr);
33 assert(ce->getNumArgs() == 0);
34 expr = ce->getImplicitObjectArgument();
37 return expr;
40 Expr const * ignoreParenImpCastAndComma(Expr const * expr) {
41 for (;;) {
42 expr = expr->IgnoreParenImpCasts();
43 auto e = dyn_cast<BinaryOperator>(expr);
44 if (e == nullptr || e->getOpcode() != BO_Comma) {
45 return expr;
47 expr = e->getRHS();
51 Expr const * getSubExprOfLogicalNegation(Expr const * expr) {
52 auto e = dyn_cast<UnaryOperator>(ignoreParenImpCastAndComma(expr));
53 return e == nullptr || e->getOpcode() != UO_LNot
54 ? nullptr : e->getSubExpr();
57 clang::Type const * stripConstRef(clang::Type const * type) {
58 auto lvalueType = dyn_cast<LValueReferenceType>(type);
59 if (!lvalueType)
60 return type;
61 return lvalueType->getPointeeType()->getUnqualifiedDesugaredType();
64 bool isCompatibleTypeForOperator(clang::Type const * paramType, CXXRecordDecl const * argRecordDecl) {
65 paramType = stripConstRef(paramType);
66 auto paramRecordType = dyn_cast<RecordType>(paramType);
67 if (!paramRecordType)
68 return false;
69 CXXRecordDecl const * paramRecordDecl = dyn_cast<CXXRecordDecl>(paramRecordType->getDecl());
70 if (!paramRecordDecl)
71 return false;
72 return argRecordDecl == paramRecordDecl || argRecordDecl->isDerivedFrom(paramRecordDecl);
75 FunctionDecl const * findMemberOperator(CXXRecordDecl const * recordDecl, OverloadedOperatorKind ooOpcode, CXXRecordDecl const * rhs) {
76 for (auto it = recordDecl->method_begin(); it != recordDecl->method_end(); ++it) {
77 if (it->getOverloadedOperator() == ooOpcode) {
78 if (it->getNumParams() == 1 && isCompatibleTypeForOperator(it->getParamDecl(0)->getType().getTypePtr(), rhs))
79 return *it;
82 return nullptr;
85 // Magic value to indicate we assume this operator exists
86 static FunctionDecl const * const ASSUME_OPERATOR_EXISTS = reinterpret_cast<FunctionDecl const *>(-1);
88 // Search for an operator with matching parameter types; while this may miss some operators with
89 // odd parameter types that would actually be used by the compiler, it is overall better to have too
90 // many false negatives (i.e., miss valid loplugin:simplifybool warnings) than false positives here:
91 FunctionDecl const * findOperator(CompilerInstance& compiler, BinaryOperator::Opcode opcode, clang::Type const * lhsType, clang::Type const * rhsType) {
92 auto lhsRecordType = dyn_cast<RecordType>(lhsType);
93 if (!lhsRecordType)
94 return nullptr;
95 auto rhsRecordType = dyn_cast<RecordType>(rhsType);
96 if (!rhsRecordType)
97 return nullptr;
98 CXXRecordDecl const * lhsRecordDecl = dyn_cast<CXXRecordDecl>(lhsRecordType->getDecl());
99 if (!lhsRecordDecl)
100 return nullptr;
101 CXXRecordDecl const * rhsRecordDecl = dyn_cast<CXXRecordDecl>(rhsRecordType->getDecl());
102 if (!rhsRecordDecl)
103 return nullptr;
105 auto ctx = lhsRecordDecl->getCanonicalDecl()->getDeclContext();
108 It looks the clang Sema::LookupOverloadedOperatorName is the chunk of functionality I need,
109 but I have no idea how to call it from here.
110 Actually finding the right standard library operators requires doing conversions and other funky stuff.
111 For now, just assume that standard library operators are well-behaved, and have negated operators.
113 if (ctx->isStdNamespace())
114 return ASSUME_OPERATOR_EXISTS;
115 if (auto namespaceDecl = dyn_cast<NamespaceDecl>(ctx)) {
116 // because, of course, half the standard library is not "in the standard namespace"
117 if (namespaceDecl->getName() == "__gnu_debug")
118 return ASSUME_OPERATOR_EXISTS;
121 // search for member overloads
122 // (using the hard way here because DeclContext::lookup does not work for member operators)
123 auto ooOpcode = BinaryOperator::getOverloadedOperator(opcode);
124 FunctionDecl const * foundFunction = findMemberOperator(lhsRecordDecl, ooOpcode, rhsRecordDecl);
125 if (foundFunction)
126 return foundFunction;
127 auto ForallBasesCallback = [&](const CXXRecordDecl *baseCXXRecordDecl)
129 if (baseCXXRecordDecl->isInvalidDecl())
130 return false;
131 foundFunction = findMemberOperator(baseCXXRecordDecl, ooOpcode, rhsRecordDecl);
132 return false;
135 lhsRecordDecl->forallBases(ForallBasesCallback);
136 if (foundFunction)
137 return foundFunction;
139 // search for free function overloads
140 if (ctx->getDeclKind() == Decl::LinkageSpec) {
141 ctx = ctx->getParent();
143 auto operatorDeclName = compiler.getASTContext().DeclarationNames.getCXXOperatorName(ooOpcode);
144 auto res = ctx->lookup(operatorDeclName);
145 for (auto d = res.begin(); d != res.end(); ++d) {
146 FunctionDecl const * f = dyn_cast<FunctionDecl>(*d);
147 if (!f || f->getNumParams() != 2)
148 continue;
149 if (!isCompatibleTypeForOperator(f->getParamDecl(0)->getType().getTypePtr(), lhsRecordDecl))
150 continue;
151 if (!isCompatibleTypeForOperator(f->getParamDecl(1)->getType().getTypePtr(), rhsRecordDecl))
152 continue;
153 return f;
155 return nullptr;
158 enum class Value { Unknown, False, True };
160 Value getValue(Expr const * expr) {
161 expr = ignoreParenImpCastAndComma(expr);
162 if (expr->getType()->isBooleanType()) {
163 // Instead going via Expr::isCXX11ConstantExpr would turn up exactly one
164 // additional place in svx/source/dialog/framelinkarray.cxx
166 // const bool DIAG_DBL_CLIP_DEFAULT = false;
167 // ...
168 // ... = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
170 // where it is unclear whether it is not actually better to consider
171 // DIAG_DBL_CLIP_DEFAULT a tunable parameter (and thus not to simplify):
172 auto lit = dyn_cast<CXXBoolLiteralExpr>(expr);
173 if (lit != nullptr) {
174 return lit->getValue() ? Value::True : Value::False;
177 return Value::Unknown;
180 class SimplifyBool:
181 public loplugin::FilteringPlugin<SimplifyBool>
183 public:
184 explicit SimplifyBool(loplugin::InstantiationData const & data):
185 FilteringPlugin(data) {}
187 void run() override;
189 bool VisitUnaryOperator(UnaryOperator const * expr);
191 bool VisitBinaryOperator(BinaryOperator const * expr);
193 bool VisitConditionalOperator(ConditionalOperator const * expr);
195 bool TraverseFunctionDecl(FunctionDecl *);
197 bool TraverseCXXMethodDecl(CXXMethodDecl *);
199 private:
200 bool visitBinLT(BinaryOperator const * expr);
202 bool visitBinGT(BinaryOperator const * expr);
204 bool visitBinLE(BinaryOperator const * expr);
206 bool visitBinGE(BinaryOperator const * expr);
208 bool visitBinEQ(BinaryOperator const * expr);
210 bool visitBinNE(BinaryOperator const * expr);
212 FunctionDecl* m_insideFunctionDecl = nullptr;
215 void SimplifyBool::run() {
216 if (compiler.getLangOpts().CPlusPlus) {
217 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
221 bool SimplifyBool::VisitUnaryOperator(UnaryOperator const * expr) {
222 if (expr->getOpcode() != UO_LNot) {
223 return true;
225 if (ignoreLocation(expr)) {
226 return true;
228 auto e = getSubExprOfLogicalNegation(expr->getSubExpr());
229 if (e) {
230 // Ignore macros, otherwise
231 // OSL_ENSURE(!b, ...);
232 // triggers.
233 if (e->getBeginLoc().isMacroID())
234 return true;
235 // double logical not of an int is an idiom to convert to bool
236 auto const sub = ignoreAllImplicit(e);
237 if (!sub->getType()->isBooleanType())
238 return true;
239 report(
240 DiagnosticsEngine::Warning,
241 ("double logical negation expression of the form '!!A' (with A of type"
242 " %0) can %select{logically|literally}1 be simplified as 'A'"),
243 expr->getBeginLoc())
244 << sub->getType()
245 << sub->getType()->isBooleanType()
246 << expr->getSourceRange();
247 return true;
249 auto sub = expr->getSubExpr()->IgnoreParenImpCasts();
250 auto reversed = false;
251 if (auto const rewritten = dyn_cast<CXXRewrittenBinaryOperator>(sub)) {
252 if (rewritten->isReversed()) {
253 if (rewritten->getOperator() == BO_EQ) {
254 auto const sem = rewritten->getSemanticForm();
255 bool match;
256 if (auto const op1 = dyn_cast<BinaryOperator>(sem)) {
257 match = op1->getOpcode() == BO_EQ;
258 } else if (auto const op2 = dyn_cast<CXXOperatorCallExpr>(sem)) {
259 match = op2->getOperator() == OO_EqualEqual;
260 } else {
261 match = false;
263 if (match) {
264 sub = sem;
265 reversed = true;
270 if (auto binaryOp = dyn_cast<BinaryOperator>(sub)) {
271 // Ignore macros, otherwise
272 // OSL_ENSURE(!b, ...);
273 // triggers.
274 if (binaryOp->getBeginLoc().isMacroID())
275 return true;
276 if (binaryOp->isComparisonOp())
278 auto t = binaryOp->getLHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
279 if (t->isTemplateTypeParmType() || t->isDependentType() || t->isRecordType())
280 return true;
281 // for floating point (with NaN) !(x<y) need not be equivalent to x>=y
282 if (t->isFloatingType() ||
283 binaryOp->getRHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType()->isFloatingType())
284 return true;
285 report(
286 DiagnosticsEngine::Warning,
287 ("logical negation of comparison operator, can be simplified by inverting operator"),
288 expr->getBeginLoc())
289 << expr->getSourceRange();
291 else if (binaryOp->isLogicalOp())
293 // if we find a negation condition inside, it is definitely better
294 // to expand it out
295 bool foundLNot = false;
296 auto containsNegationOrComparison = [&](Expr const * expr) {
297 expr = ignoreParenImpCastAndComma(expr);
298 if (auto unaryOp = dyn_cast<UnaryOperator>(expr))
299 if (unaryOp->getOpcode() == UO_LNot)
301 foundLNot = true;
302 return expr;
304 if (auto binaryOp = dyn_cast<BinaryOperator>(expr))
305 if (binaryOp->isComparisonOp())
306 return expr;
307 if (auto cxxOpCall = dyn_cast<CXXOperatorCallExpr>(expr))
308 if (cxxOpCall->isComparisonOp())
309 return expr;
310 return (Expr const*)nullptr;
312 auto lhs = containsNegationOrComparison(binaryOp->getLHS());
313 auto rhs = containsNegationOrComparison(binaryOp->getRHS());
314 if (foundLNot || (lhs && rhs))
315 report(
316 DiagnosticsEngine::Warning,
317 ("logical negation of logical op containing negation, can be simplified"),
318 binaryOp->getBeginLoc())
319 << binaryOp->getSourceRange();
322 if (auto binaryOp = dyn_cast<CXXOperatorCallExpr>(sub)) {
323 // Ignore macros, otherwise
324 // OSL_ENSURE(!b, ...);
325 // triggers.
326 if (binaryOp->getBeginLoc().isMacroID())
327 return true;
328 auto op = binaryOp->getOperator();
329 // Negating things like > and >= would probably not be wise, there is no guarantee the negation holds for operator overloaded types.
330 // However, == and != are normally considered ok.
331 if (!(op == OO_EqualEqual || op == OO_ExclaimEqual))
332 return true;
333 BinaryOperator::Opcode negatedOpcode = BinaryOperator::negateComparisonOp(BinaryOperator::getOverloadedOpcode(op));
334 auto lhs = binaryOp->getArg(reversed ? 1 : 0)->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
335 auto rhs = binaryOp->getArg(reversed ? 0 : 1)->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
336 auto const negOp = findOperator(compiler, negatedOpcode, lhs, rhs);
337 if (!negOp)
338 return true;
339 // if we are inside a similar operator, ignore, eg. operator!= is often defined by calling !operator==
340 if (m_insideFunctionDecl && m_insideFunctionDecl->getNumParams() >= 1) {
341 auto t = stripConstRef(m_insideFunctionDecl->getParamDecl(0)->getType().getTypePtr());
342 if (t == lhs)
343 return true;
345 // QA code
346 StringRef fn(handler.getMainFileName());
347 if (loplugin::isSamePathname(fn, SRCDIR "/testtools/source/bridgetest/bridgetest.cxx"))
348 return true;
349 report(
350 DiagnosticsEngine::Warning,
351 ("logical negation of comparison operator, can be simplified by inverting operator"),
352 expr->getBeginLoc())
353 << expr->getSourceRange();
354 if (negOp != ASSUME_OPERATOR_EXISTS)
355 report(
356 DiagnosticsEngine::Note, "the presumed corresponding negated operator for %0 and %1 is declared here",
357 negOp->getLocation())
358 << binaryOp->getArg(reversed ? 1 : 0)->IgnoreImpCasts()->getType()
359 << binaryOp->getArg(reversed ? 0 : 1)->IgnoreImpCasts()->getType()
360 << negOp->getSourceRange();
362 return true;
365 bool SimplifyBool::VisitBinaryOperator(BinaryOperator const * expr) {
366 switch (expr->getOpcode()) {
367 case BO_LT:
368 return visitBinLT(expr);
369 case BO_GT:
370 return visitBinGT(expr);
371 case BO_LE:
372 return visitBinLE(expr);
373 case BO_GE:
374 return visitBinGE(expr);
375 case BO_EQ:
376 return visitBinEQ(expr);
377 case BO_NE:
378 return visitBinNE(expr);
379 default:
380 return true;
384 bool SimplifyBool::visitBinLT(BinaryOperator const * expr) {
385 if (ignoreLocation(expr)) {
386 return true;
388 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
389 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
391 return true;
393 auto v1 = getValue(expr->getLHS());
394 auto v2 = getValue(expr->getRHS());
395 switch (v1) {
396 case Value::Unknown:
397 switch (v2) {
398 case Value::Unknown:
399 break;
400 case Value::False:
401 report(
402 DiagnosticsEngine::Warning,
403 ("less-than expression of the form 'A < false' (with A of type"
404 " %0) can logically be simplified as 'false'"),
405 expr->getBeginLoc())
406 << expr->getLHS()->IgnoreImpCasts()->getType()
407 << expr->getSourceRange();
408 break;
409 case Value::True:
411 auto e = getSubExprOfLogicalNegation(expr->getLHS());
412 if (e == nullptr) {
413 report(
414 DiagnosticsEngine::Warning,
415 ("less-than expression of the form 'A < true' (with A"
416 " of type %0) can %select{logically|literally}1 be"
417 " simplified as '!A'"),
418 expr->getBeginLoc())
419 << expr->getLHS()->IgnoreImpCasts()->getType()
420 << (expr->getLHS()->IgnoreImpCasts()->getType()
421 ->isBooleanType())
422 << expr->getSourceRange();
423 } else {
424 report(
425 DiagnosticsEngine::Warning,
426 ("less-than expression of the form '!A < true' (with A"
427 " of type %0) can %select{logically|literally}1 be"
428 " simplified as 'A'"),
429 expr->getBeginLoc())
430 << e->IgnoreImpCasts()->getType()
431 << e->IgnoreImpCasts()->getType()->isBooleanType()
432 << expr->getSourceRange();
434 break;
437 break;
438 case Value::False:
439 switch (v2) {
440 case Value::Unknown:
441 report(
442 DiagnosticsEngine::Warning,
443 ("less-than expression of the form 'false < A' (with A of type"
444 " %0) can %select{logically|literally}1 be simplified as 'A'"),
445 expr->getBeginLoc())
446 << expr->getRHS()->IgnoreImpCasts()->getType()
447 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
448 << expr->getSourceRange();
449 break;
450 case Value::False:
451 report(
452 DiagnosticsEngine::Warning,
453 ("less-than expression of the form 'false < false' can"
454 " literally be simplified as 'false'"),
455 expr->getBeginLoc())
456 << expr->getSourceRange();
457 break;
458 case Value::True:
459 report(
460 DiagnosticsEngine::Warning,
461 ("less-than expression of the form 'false < true' can"
462 " literally be simplified as 'true'"),
463 expr->getBeginLoc())
464 << expr->getSourceRange();
465 break;
467 break;
468 case Value::True:
469 switch (v2) {
470 case Value::Unknown:
471 report(
472 DiagnosticsEngine::Warning,
473 ("less-than expression of the form 'true < A' (with A of type"
474 " %0) can logically be simplified as 'false'"),
475 expr->getBeginLoc())
476 << expr->getRHS()->IgnoreImpCasts()->getType()
477 << expr->getSourceRange();
478 break;
479 case Value::False:
480 report(
481 DiagnosticsEngine::Warning,
482 ("less-than expression of the form 'true < false' can"
483 " literally be simplified as 'false'"),
484 expr->getBeginLoc())
485 << expr->getSourceRange();
486 break;
487 case Value::True:
488 report(
489 DiagnosticsEngine::Warning,
490 ("less-than expression of the form 'true < true' can"
491 " literally be simplified as 'false'"),
492 expr->getBeginLoc())
493 << expr->getSourceRange();
494 break;
496 break;
498 return true;
501 bool SimplifyBool::visitBinGT(BinaryOperator const * expr) {
502 if (ignoreLocation(expr)) {
503 return true;
505 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
506 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
508 return true;
510 auto v1 = getValue(expr->getLHS());
511 auto v2 = getValue(expr->getRHS());
512 switch (v1) {
513 case Value::Unknown:
514 switch (v2) {
515 case Value::Unknown:
516 break;
517 case Value::False:
518 report(
519 DiagnosticsEngine::Warning,
520 ("greater-than expression of the form 'A > false' (with A of"
521 " type %0) can %select{logically|literally}1 be simplified as"
522 " 'A'"),
523 expr->getBeginLoc())
524 << expr->getLHS()->IgnoreImpCasts()->getType()
525 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
526 << expr->getSourceRange();
527 break;
528 case Value::True:
529 report(
530 DiagnosticsEngine::Warning,
531 ("greater-than expression of the form 'A > true' (with A of"
532 " type %0) can logically be simplified as 'false'"),
533 expr->getBeginLoc())
534 << expr->getLHS()->IgnoreImpCasts()->getType()
535 << expr->getSourceRange();
536 break;
538 break;
539 case Value::False:
540 switch (v2) {
541 case Value::Unknown:
542 report(
543 DiagnosticsEngine::Warning,
544 ("greater-than expression of the form 'false > A' (with A of"
545 " type %0) can logically be simplified as 'false'"),
546 expr->getBeginLoc())
547 << expr->getRHS()->IgnoreImpCasts()->getType()
548 << expr->getSourceRange();
549 break;
550 case Value::False:
551 report(
552 DiagnosticsEngine::Warning,
553 ("greater-than expression of the form 'false > false' can"
554 " literally be simplified as 'false'"),
555 expr->getBeginLoc())
556 << expr->getSourceRange();
557 break;
558 case Value::True:
559 report(
560 DiagnosticsEngine::Warning,
561 ("greater-than expression of the form 'false > true' can"
562 " literally be simplified as 'false'"),
563 expr->getBeginLoc())
564 << expr->getSourceRange();
565 break;
567 break;
568 case Value::True:
569 switch (v2) {
570 case Value::Unknown:
572 auto e = getSubExprOfLogicalNegation(expr->getRHS());
573 if (e == nullptr) {
574 report(
575 DiagnosticsEngine::Warning,
576 ("greater-than expression of the form 'true > A' (with"
577 " A of type %0) can %select{logically|literally}1 be"
578 " simplified as '!A'"),
579 expr->getBeginLoc())
580 << expr->getRHS()->IgnoreImpCasts()->getType()
581 << (expr->getRHS()->IgnoreImpCasts()->getType()
582 ->isBooleanType())
583 << expr->getSourceRange();
584 } else {
585 report(
586 DiagnosticsEngine::Warning,
587 ("greater-than expression of the form 'true > !A' (with"
588 " A of type %0) can %select{logically|literally}1 be"
589 " simplified as 'A'"),
590 expr->getBeginLoc())
591 << e->IgnoreImpCasts()->getType()
592 << e->IgnoreImpCasts()->getType()->isBooleanType()
593 << expr->getSourceRange();
595 break;
597 case Value::False:
598 report(
599 DiagnosticsEngine::Warning,
600 ("greater-than expression of the form 'true > false' can"
601 " literally be simplified as 'true'"),
602 expr->getBeginLoc())
603 << expr->getSourceRange();
604 break;
605 case Value::True:
606 report(
607 DiagnosticsEngine::Warning,
608 ("greater-than expression of the form 'true > true' can"
609 " literally be simplified as 'false'"),
610 expr->getBeginLoc())
611 << expr->getSourceRange();
612 break;
614 break;
616 return true;
619 bool SimplifyBool::visitBinLE(BinaryOperator const * expr) {
620 if (ignoreLocation(expr)) {
621 return true;
623 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
624 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
626 return true;
628 auto v1 = getValue(expr->getLHS());
629 auto v2 = getValue(expr->getRHS());
630 switch (v1) {
631 case Value::Unknown:
632 switch (v2) {
633 case Value::Unknown:
634 break;
635 case Value::False:
637 auto e = getSubExprOfLogicalNegation(expr->getLHS());
638 if (e == nullptr) {
639 report(
640 DiagnosticsEngine::Warning,
641 ("less-than-or-equal-to expression of the form 'A <="
642 " false' (with A of type %0) can"
643 " %select{logically|literally}1 be simplified as"
644 " '!A'"),
645 expr->getBeginLoc())
646 << expr->getLHS()->IgnoreImpCasts()->getType()
647 << (expr->getLHS()->IgnoreImpCasts()->getType()
648 ->isBooleanType())
649 << expr->getSourceRange();
650 } else {
651 report(
652 DiagnosticsEngine::Warning,
653 ("less-than-or-equal-to expression of the form '!A <="
654 " false' (with A of type %0) can"
655 " %select{logically|literally}1 be simplified as 'A'"),
656 expr->getBeginLoc())
657 << e->IgnoreImpCasts()->getType()
658 << e->IgnoreImpCasts()->getType()->isBooleanType()
659 << expr->getSourceRange();
661 break;
663 case Value::True:
664 report(
665 DiagnosticsEngine::Warning,
666 ("less-than-or-equal-to expression of the form 'A <= true'"
667 " (with A of type %0) can logically be simplified as 'true'"),
668 expr->getBeginLoc())
669 << expr->getLHS()->IgnoreImpCasts()->getType()
670 << expr->getSourceRange();
671 break;
673 break;
674 case Value::False:
675 switch (v2) {
676 case Value::Unknown:
677 report(
678 DiagnosticsEngine::Warning,
679 ("less-than-or-equal-to expression of the form 'false <= A'"
680 " (with A of type %0) can logically be simplified as 'true'"),
681 expr->getBeginLoc())
682 << expr->getRHS()->IgnoreImpCasts()->getType()
683 << expr->getSourceRange();
684 break;
685 case Value::False:
686 report(
687 DiagnosticsEngine::Warning,
688 ("less-than-or-equal-to expression of the form 'false <= false'"
689 " can literally be simplified as 'true'"),
690 expr->getBeginLoc())
691 << expr->getSourceRange();
692 break;
693 case Value::True:
694 report(
695 DiagnosticsEngine::Warning,
696 ("less-than-or-equal-to expression of the form 'false <= true'"
697 " can literally be simplified as 'true'"),
698 expr->getBeginLoc())
699 << expr->getSourceRange();
700 break;
702 break;
703 case Value::True:
704 switch (v2) {
705 case Value::Unknown:
706 report(
707 DiagnosticsEngine::Warning,
708 ("less-than-or-equal-to expression of the form 'true <= A'"
709 " (with A of type %0) can %select{logically|literally}1 be"
710 " simplified as 'A'"),
711 expr->getBeginLoc())
712 << expr->getRHS()->IgnoreImpCasts()->getType()
713 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
714 << expr->getSourceRange();
715 break;
716 case Value::False:
717 report(
718 DiagnosticsEngine::Warning,
719 ("less-than-or-equal-to expression of the form 'true <= false'"
720 " can literally be simplified as 'false'"),
721 expr->getBeginLoc())
722 << expr->getSourceRange();
723 break;
724 case Value::True:
725 report(
726 DiagnosticsEngine::Warning,
727 ("less-than-or-equal-to expression of the form 'true <= true'"
728 " can literally be simplified as 'true'"),
729 expr->getBeginLoc())
730 << expr->getSourceRange();
731 break;
733 break;
735 return true;
738 bool SimplifyBool::visitBinGE(BinaryOperator const * expr) {
739 if (ignoreLocation(expr)) {
740 return true;
742 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
743 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
745 return true;
747 auto v1 = getValue(expr->getLHS());
748 auto v2 = getValue(expr->getRHS());
749 switch (v1) {
750 case Value::Unknown:
751 switch (v2) {
752 case Value::Unknown:
753 break;
754 case Value::False:
755 report(
756 DiagnosticsEngine::Warning,
757 ("greater-than-or-equal-to expression of the form 'A >= false'"
758 " (with A of type %0) can logically be simplified as 'true'"),
759 expr->getBeginLoc())
760 << expr->getLHS()->IgnoreImpCasts()->getType()
761 << expr->getSourceRange();
762 break;
763 case Value::True:
764 report(
765 DiagnosticsEngine::Warning,
766 ("greater-than-or-equal-to expression of the form 'A >= true'"
767 " (with A of type %0) can %select{logically|literally}1 be"
768 " simplified as 'A'"),
769 expr->getBeginLoc())
770 << expr->getLHS()->IgnoreImpCasts()->getType()
771 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
772 << expr->getSourceRange();
773 break;
775 break;
776 case Value::False:
777 switch (v2) {
778 case Value::Unknown:
780 auto e = getSubExprOfLogicalNegation(expr->getRHS());
781 if (e == nullptr) {
782 report(
783 DiagnosticsEngine::Warning,
784 ("greater-than-or-equal-to expression of the form"
785 " 'false >= A' (with A of type %0) can"
786 " %select{logically|literally}1 be simplified as"
787 " '!A'"),
788 expr->getBeginLoc())
789 << expr->getRHS()->IgnoreImpCasts()->getType()
790 << (expr->getRHS()->IgnoreImpCasts()->getType()
791 ->isBooleanType())
792 << expr->getSourceRange();
793 } else {
794 report(
795 DiagnosticsEngine::Warning,
796 ("greater-than-or-equal-to expression of the form"
797 " 'false >= !A' (with A of type %0) can"
798 " %select{logically|literally}1 be simplified as 'A'"),
799 expr->getBeginLoc())
800 << e->IgnoreImpCasts()->getType()
801 << e->IgnoreImpCasts()->getType()->isBooleanType()
802 << expr->getSourceRange();
804 break;
806 case Value::False:
807 report(
808 DiagnosticsEngine::Warning,
809 ("greater-than-or-equal-to expression of the form 'false >="
810 " false' can literally be simplified as 'true'"),
811 expr->getBeginLoc())
812 << expr->getSourceRange();
813 break;
814 case Value::True:
815 report(
816 DiagnosticsEngine::Warning,
817 ("greater-than-or-equal-to expression of the form 'false >="
818 " true' can literally be simplified as 'false'"),
819 expr->getBeginLoc())
820 << expr->getSourceRange();
821 break;
823 break;
824 case Value::True:
825 switch (v2) {
826 case Value::Unknown:
827 report(
828 DiagnosticsEngine::Warning,
829 ("greater-than-or-equal-to expression of the form 'true >= A'"
830 " (with A of type %0) can logically be simplified as 'true'"),
831 expr->getBeginLoc())
832 << expr->getRHS()->IgnoreImpCasts()->getType()
833 << expr->getSourceRange();
834 break;
835 case Value::False:
836 report(
837 DiagnosticsEngine::Warning,
838 ("greater-than-or-equal-to expression of the form 'true >="
839 " false' can literally be simplified as 'true'"),
840 expr->getBeginLoc())
841 << expr->getSourceRange();
842 break;
843 case Value::True:
844 report(
845 DiagnosticsEngine::Warning,
846 ("greater-than-or-equal-to expression of the form 'true >="
847 " true' can literally be simplified as 'true'"),
848 expr->getBeginLoc())
849 << expr->getSourceRange();
850 break;
852 break;
854 return true;
857 bool SimplifyBool::visitBinEQ(BinaryOperator const * expr) {
858 if (ignoreLocation(expr)) {
859 return true;
861 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
862 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
864 return true;
866 auto v1 = getValue(expr->getLHS());
867 auto v2 = getValue(expr->getRHS());
868 switch (v1) {
869 case Value::Unknown:
870 switch (v2) {
871 case Value::Unknown:
872 break;
873 case Value::False:
875 auto e = getSubExprOfLogicalNegation(expr->getLHS());
876 if (e == nullptr) {
877 report(
878 DiagnosticsEngine::Warning,
879 ("equal-to expression of the form 'A == false' (with A"
880 " of type %0) can %select{logically|literally}1 be"
881 " simplified as '!A'"),
882 expr->getBeginLoc())
883 << expr->getLHS()->IgnoreImpCasts()->getType()
884 << (expr->getLHS()->IgnoreImpCasts()->getType()
885 ->isBooleanType())
886 << expr->getSourceRange();
887 } else {
888 report(
889 DiagnosticsEngine::Warning,
890 ("equal-to expression of the form '!A == false' (with A"
891 " of type %0) can %select{logically|literally}1 be"
892 " simplified as 'A'"),
893 expr->getBeginLoc())
894 << e->IgnoreImpCasts()->getType()
895 << e->IgnoreImpCasts()->getType()->isBooleanType()
896 << expr->getSourceRange();
898 break;
900 case Value::True:
901 report(
902 DiagnosticsEngine::Warning,
903 ("equal-to expression of the form 'A == true' (with A of type"
904 " %0) can %select{logically|literally}1 be simplified as 'A'"),
905 expr->getBeginLoc())
906 << expr->getLHS()->IgnoreImpCasts()->getType()
907 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
908 << expr->getSourceRange();
909 break;
911 break;
912 case Value::False:
913 switch (v2) {
914 case Value::Unknown:
916 auto e = getSubExprOfLogicalNegation(expr->getRHS());
917 if (e == nullptr) {
918 report(
919 DiagnosticsEngine::Warning,
920 ("equal-to expression of the form 'false == A' (with A"
921 " of type %0) can %select{logically|literally}1 be"
922 " simplified as '!A'"),
923 expr->getBeginLoc())
924 << expr->getRHS()->IgnoreImpCasts()->getType()
925 << (expr->getRHS()->IgnoreImpCasts()->getType()
926 ->isBooleanType())
927 << expr->getSourceRange();
928 } else {
929 report(
930 DiagnosticsEngine::Warning,
931 ("equal-to expression of the form 'false == !A' (with A"
932 " of type %0) can %select{logically|literally}1 be"
933 " simplified as 'A'"),
934 expr->getBeginLoc())
935 << e->IgnoreImpCasts()->getType()
936 << e->IgnoreImpCasts()->getType()->isBooleanType()
937 << expr->getSourceRange();
939 break;
941 case Value::False:
942 report(
943 DiagnosticsEngine::Warning,
944 ("equal-to expression of the form 'false == false' can"
945 " literally be simplified as 'true'"),
946 expr->getBeginLoc())
947 << expr->getSourceRange();
948 break;
949 case Value::True:
950 report(
951 DiagnosticsEngine::Warning,
952 ("equal-to expression of the form 'false == true' can"
953 " literally be simplified as 'false'"),
954 expr->getBeginLoc())
955 << expr->getSourceRange();
956 break;
958 break;
959 case Value::True:
960 switch (v2) {
961 case Value::Unknown:
962 report(
963 DiagnosticsEngine::Warning,
964 ("equal-to expression of the form 'true == A' (with A of type"
965 " %0) can %select{logically|literally}1 be simplified as 'A'"),
966 expr->getBeginLoc())
967 << expr->getRHS()->IgnoreImpCasts()->getType()
968 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
969 << expr->getSourceRange();
970 break;
971 case Value::False:
972 report(
973 DiagnosticsEngine::Warning,
974 ("equal-to expression of the form 'true == false' can"
975 " literally be simplified as 'false'"),
976 expr->getBeginLoc())
977 << expr->getSourceRange();
978 break;
979 case Value::True:
980 report(
981 DiagnosticsEngine::Warning,
982 ("equal-to expression of the form 'true == true' can"
983 " literally be simplified as 'true'"),
984 expr->getBeginLoc())
985 << expr->getSourceRange();
986 break;
988 break;
990 return true;
993 bool SimplifyBool::visitBinNE(BinaryOperator const * expr) {
994 if (ignoreLocation(expr)) {
995 return true;
997 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
998 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
1000 return true;
1002 auto v1 = getValue(expr->getLHS());
1003 auto v2 = getValue(expr->getRHS());
1004 switch (v1) {
1005 case Value::Unknown:
1006 switch (v2) {
1007 case Value::Unknown:
1008 break;
1009 case Value::False:
1010 report(
1011 DiagnosticsEngine::Warning,
1012 ("not-equal-to expression of the form 'A != false' (with A of"
1013 " type %0) can %select{logically|literally}1 be simplified as"
1014 " 'A'"),
1015 expr->getBeginLoc())
1016 << expr->getLHS()->IgnoreImpCasts()->getType()
1017 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
1018 << expr->getSourceRange();
1019 break;
1020 case Value::True:
1022 auto e = getSubExprOfLogicalNegation(expr->getLHS());
1023 if (e == nullptr) {
1024 report(
1025 DiagnosticsEngine::Warning,
1026 ("not-equal-to expression of the form 'A != true' (with"
1027 " A of type %0) can %select{logically|literally}1 be"
1028 " simplified as '!A'"),
1029 expr->getBeginLoc())
1030 << expr->getLHS()->IgnoreImpCasts()->getType()
1031 << (expr->getLHS()->IgnoreImpCasts()->getType()
1032 ->isBooleanType())
1033 << expr->getSourceRange();
1034 } else {
1035 report(
1036 DiagnosticsEngine::Warning,
1037 ("not-equal-to expression of the form '!A != true'"
1038 " (with A of type %0) can"
1039 " %select{logically|literally}1 be simplified as 'A'"),
1040 expr->getBeginLoc())
1041 << e->IgnoreImpCasts()->getType()
1042 << e->IgnoreImpCasts()->getType()->isBooleanType()
1043 << expr->getSourceRange();
1045 break;
1048 break;
1049 case Value::False:
1050 switch (v2) {
1051 case Value::Unknown:
1052 report(
1053 DiagnosticsEngine::Warning,
1054 ("not-equal-to expression of the form 'false != A' (with A of"
1055 " type %0) can %select{logically|literally}1 be simplified as"
1056 " 'A'"),
1057 expr->getBeginLoc())
1058 << expr->getRHS()->IgnoreImpCasts()->getType()
1059 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
1060 << expr->getSourceRange();
1061 break;
1062 case Value::False:
1063 report(
1064 DiagnosticsEngine::Warning,
1065 ("not-equal-to expression of the form 'false != false' can"
1066 " literally be simplified as 'false'"),
1067 expr->getBeginLoc())
1068 << expr->getSourceRange();
1069 break;
1070 case Value::True:
1071 report(
1072 DiagnosticsEngine::Warning,
1073 ("not-equal-to expression of the form 'false != true' can"
1074 " literally be simplified as 'true'"),
1075 expr->getBeginLoc())
1076 << expr->getSourceRange();
1077 break;
1079 break;
1080 case Value::True:
1081 switch (v2) {
1082 case Value::Unknown:
1084 auto e = getSubExprOfLogicalNegation(expr->getRHS());
1085 if (e == nullptr) {
1086 report(
1087 DiagnosticsEngine::Warning,
1088 ("not-equal-to expression of the form 'true != A' (with"
1089 " A of type %0) can %select{logically|literally}1 be"
1090 " simplified as '!A'"),
1091 expr->getBeginLoc())
1092 << expr->getRHS()->IgnoreImpCasts()->getType()
1093 << (expr->getRHS()->IgnoreImpCasts()->getType()
1094 ->isBooleanType())
1095 << expr->getSourceRange();
1096 } else {
1097 report(
1098 DiagnosticsEngine::Warning,
1099 ("not-equal-to expression of the form 'true != !A'"
1100 " (with A of type %0) can"
1101 " %select{logically|literally}1 be simplified as 'A'"),
1102 expr->getBeginLoc())
1103 << e->IgnoreImpCasts()->getType()
1104 << e->IgnoreImpCasts()->getType()->isBooleanType()
1105 << expr->getSourceRange();
1107 break;
1109 case Value::False:
1110 report(
1111 DiagnosticsEngine::Warning,
1112 ("not-equal-to expression of the form 'true != false' can"
1113 " literally be simplified as 'true'"),
1114 expr->getBeginLoc())
1115 << expr->getSourceRange();
1116 break;
1117 case Value::True:
1118 report(
1119 DiagnosticsEngine::Warning,
1120 ("not-equal-to expression of the form 'true != true' can"
1121 " literally be simplified as 'false'"),
1122 expr->getBeginLoc())
1123 << expr->getSourceRange();
1124 break;
1126 break;
1128 return true;
1131 bool SimplifyBool::VisitConditionalOperator(ConditionalOperator const * expr) {
1132 if (ignoreLocation(expr)) {
1133 return true;
1135 auto v1 = getValue(expr->getTrueExpr());
1136 auto v2 = getValue(expr->getFalseExpr());
1137 switch (v1) {
1138 case Value::Unknown:
1139 switch (v2) {
1140 case Value::Unknown:
1141 break;
1142 case Value::False:
1143 report(
1144 DiagnosticsEngine::Warning,
1145 ("conditional expression of the form 'A ? B : false' (with A of"
1146 " type %0 and B of type %1) can %select{logically|literally}2"
1147 " be simplified as 'A && B'"),
1148 expr->getBeginLoc())
1149 << expr->getCond()->IgnoreImpCasts()->getType()
1150 << expr->getTrueExpr()->IgnoreImpCasts()->getType()
1151 << ((expr->getCond()->IgnoreImpCasts()->getType()
1152 ->isBooleanType())
1153 && (expr->getTrueExpr()->IgnoreImpCasts()->getType()
1154 ->isBooleanType()))
1155 << expr->getSourceRange();
1156 break;
1157 case Value::True:
1159 auto e = getSubExprOfLogicalNegation(expr->getCond());
1160 if (e == nullptr) {
1161 report(
1162 DiagnosticsEngine::Warning,
1163 ("conditional expression of the form 'A ? B : true'"
1164 " (with A of type %0 and B of type %1) can"
1165 " %select{logically|literally}2 be simplified as '!A"
1166 " || B'"),
1167 expr->getBeginLoc())
1168 << expr->getCond()->IgnoreImpCasts()->getType()
1169 << expr->getTrueExpr()->IgnoreImpCasts()->getType()
1170 << ((expr->getCond()->IgnoreImpCasts()->getType()
1171 ->isBooleanType())
1172 && (expr->getTrueExpr()->IgnoreImpCasts()->getType()
1173 ->isBooleanType()))
1174 << expr->getSourceRange();
1175 } else {
1176 report(
1177 DiagnosticsEngine::Warning,
1178 ("conditional expression of the form '!A ? B : true'"
1179 " (with A of type %0 and B of type %1) can"
1180 " %select{logically|literally}2 be simplified as 'A ||"
1181 " B'"),
1182 expr->getBeginLoc())
1183 << e->IgnoreImpCasts()->getType()
1184 << expr->getTrueExpr()->IgnoreImpCasts()->getType()
1185 << (e->IgnoreImpCasts()->getType()->isBooleanType()
1186 && (expr->getTrueExpr()->IgnoreImpCasts()
1187 ->getType()->isBooleanType()))
1188 << expr->getSourceRange();
1190 break;
1193 break;
1194 case Value::False:
1195 switch (v2) {
1196 case Value::Unknown:
1198 auto e = getSubExprOfLogicalNegation(expr->getCond());
1199 if (e == nullptr) {
1200 report(
1201 DiagnosticsEngine::Warning,
1202 ("conditional expression of the form 'A ? false : B'"
1203 " (with A of type %0 and B of type %1) can"
1204 " %select{logically|literally}2 be simplified as '!A"
1205 " && B'"),
1206 expr->getBeginLoc())
1207 << expr->getCond()->IgnoreImpCasts()->getType()
1208 << expr->getFalseExpr()->IgnoreImpCasts()->getType()
1209 << ((expr->getCond()->IgnoreImpCasts()->getType()
1210 ->isBooleanType())
1211 && (expr->getFalseExpr()->IgnoreImpCasts()
1212 ->getType()->isBooleanType()))
1213 << expr->getSourceRange();
1214 } else {
1215 report(
1216 DiagnosticsEngine::Warning,
1217 ("conditional expression of the form '!A ? false : B'"
1218 " (with A of type %0 and B of type %1) can"
1219 " %select{logically|literally}2 be simplified as 'A &&"
1220 " B'"),
1221 expr->getBeginLoc())
1222 << e->IgnoreImpCasts()->getType()
1223 << expr->getFalseExpr()->IgnoreImpCasts()->getType()
1224 << (e->IgnoreImpCasts()->getType()->isBooleanType()
1225 && (expr->getFalseExpr()->IgnoreImpCasts()
1226 ->getType()->isBooleanType()))
1227 << expr->getSourceRange();
1229 break;
1231 case Value::False:
1232 report(
1233 DiagnosticsEngine::Warning,
1234 ("conditional expression of the form 'A ? false : false' (with"
1235 " A of type %0) can logically be simplified as 'false'"),
1236 expr->getBeginLoc())
1237 << expr->getCond()->IgnoreImpCasts()->getType()
1238 << expr->getSourceRange();
1239 break;
1240 case Value::True:
1242 auto e = getSubExprOfLogicalNegation(expr->getCond());
1243 if (e == nullptr) {
1244 report(
1245 DiagnosticsEngine::Warning,
1246 ("conditional expression of the form 'A ? false : true'"
1247 " (with A of type %0) can"
1248 " %select{logically|literally}1 be simplified as"
1249 " '!A'"),
1250 expr->getBeginLoc())
1251 << expr->getCond()->IgnoreImpCasts()->getType()
1252 << (expr->getCond()->IgnoreImpCasts()->getType()
1253 ->isBooleanType())
1254 << expr->getSourceRange();
1255 } else {
1256 report(
1257 DiagnosticsEngine::Warning,
1258 ("conditional expression of the form '!A ? false :"
1259 " true' (with A of type %0) can"
1260 " %select{logically|literally}1 be simplified as 'A'"),
1261 expr->getBeginLoc())
1262 << e->IgnoreImpCasts()->getType()
1263 << e->IgnoreImpCasts()->getType()->isBooleanType()
1264 << expr->getSourceRange();
1266 break;
1269 break;
1270 case Value::True:
1271 switch (v2) {
1272 case Value::Unknown:
1273 report(
1274 DiagnosticsEngine::Warning,
1275 ("conditional expression of the form 'A ? true : B' (with A of"
1276 " type %0 and B of type %1) can %select{logically|literally}2"
1277 " be simplified as 'A || B'"),
1278 expr->getBeginLoc())
1279 << expr->getCond()->IgnoreImpCasts()->getType()
1280 << expr->getFalseExpr()->IgnoreImpCasts()->getType()
1281 << ((expr->getCond()->IgnoreImpCasts()->getType()
1282 ->isBooleanType())
1283 && (expr->getFalseExpr()->IgnoreImpCasts()->getType()
1284 ->isBooleanType()))
1285 << expr->getSourceRange();
1286 break;
1287 case Value::False:
1288 report(
1289 DiagnosticsEngine::Warning,
1290 ("conditional expression of the form 'A ? true : false' (with A"
1291 " of type %0) can %select{logically|literally}1 be simplified"
1292 " as 'A'"),
1293 expr->getBeginLoc())
1294 << expr->getCond()->IgnoreImpCasts()->getType()
1295 << expr->getCond()->IgnoreImpCasts()->getType()->isBooleanType()
1296 << expr->getSourceRange();
1297 break;
1298 case Value::True:
1299 report(
1300 DiagnosticsEngine::Warning,
1301 ("conditional expression of the form 'A ? true : true' (with A"
1302 " of type %0) can logically be simplified as 'true'"),
1303 expr->getBeginLoc())
1304 << expr->getCond()->IgnoreImpCasts()->getType()
1305 << expr->getSourceRange();
1306 break;
1308 break;
1310 return true;
1313 bool SimplifyBool::TraverseFunctionDecl(FunctionDecl * functionDecl) {
1314 auto copy = m_insideFunctionDecl;
1315 m_insideFunctionDecl = functionDecl;
1316 bool ret = RecursiveASTVisitor::TraverseFunctionDecl(functionDecl);
1317 m_insideFunctionDecl = copy;
1318 return ret;
1321 bool SimplifyBool::TraverseCXXMethodDecl(CXXMethodDecl * functionDecl) {
1322 auto copy = m_insideFunctionDecl;
1323 m_insideFunctionDecl = functionDecl;
1324 bool ret = RecursiveASTVisitor::TraverseCXXMethodDecl(functionDecl);
1325 m_insideFunctionDecl = copy;
1326 return ret;
1329 loplugin::Plugin::Registration<SimplifyBool> X("simplifybool");
1333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */