Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / compilerplugins / clang / simplifybool.cxx
blob9167014f8c842479fb8d996fae2d84becffcdbd2
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"
14 namespace {
16 // Like clang::Stmt::IgnoreImplicit (lib/AST/Stmt.cpp), but also looking through implicit
17 // UserDefinedConversion's member function call:
18 Expr const * ignoreAllImplicit(Expr const * expr) {
19 if (auto const e = dyn_cast<ExprWithCleanups>(expr)) {
20 expr = e->getSubExpr();
22 if (auto const e = dyn_cast<MaterializeTemporaryExpr>(expr)) {
23 expr = e->GetTemporaryExpr();
25 if (auto const e = dyn_cast<CXXBindTemporaryExpr>(expr)) {
26 expr = e->getSubExpr();
28 while (auto const e = dyn_cast<ImplicitCastExpr>(expr)) {
29 expr = e->getSubExpr();
30 if (e->getCastKind() == CK_UserDefinedConversion) {
31 auto const ce = cast<CXXMemberCallExpr>(expr);
32 assert(ce->getNumArgs() == 0);
33 expr = ce->getImplicitObjectArgument();
36 return expr;
39 Expr const * ignoreParenImpCastAndComma(Expr const * expr) {
40 for (;;) {
41 expr = expr->IgnoreParenImpCasts();
42 auto e = dyn_cast<BinaryOperator>(expr);
43 if (e == nullptr || e->getOpcode() != BO_Comma) {
44 return expr;
46 expr = e->getRHS();
50 Expr const * getSubExprOfLogicalNegation(Expr const * expr) {
51 auto e = dyn_cast<UnaryOperator>(ignoreParenImpCastAndComma(expr));
52 return e == nullptr || e->getOpcode() != UO_LNot
53 ? nullptr : e->getSubExpr();
56 enum class Value { Unknown, False, True };
58 Value getValue(Expr const * expr) {
59 expr = ignoreParenImpCastAndComma(expr);
60 if (expr->getType()->isBooleanType()) {
61 // Instead going via Expr::isCXX11ConstantExpr would turn up exactly one
62 // additional place in svx/source/dialog/framelinkarray.cxx
64 // const bool DIAG_DBL_CLIP_DEFAULT = false;
65 // ...
66 // ... = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
68 // where it is unclear whether it is not actually better to consider
69 // DIAG_DBL_CLIP_DEFAULT a tunable parameter (and thus not to simplify):
70 auto lit = dyn_cast<CXXBoolLiteralExpr>(expr);
71 if (lit != nullptr) {
72 return lit->getValue() ? Value::True : Value::False;
75 return Value::Unknown;
78 class SimplifyBool:
79 public RecursiveASTVisitor<SimplifyBool>, public loplugin::Plugin
81 public:
82 explicit SimplifyBool(loplugin::InstantiationData const & data):
83 Plugin(data) {}
85 void run() override;
87 bool VisitUnaryLNot(UnaryOperator const * expr);
89 bool VisitBinLT(BinaryOperator const * expr);
91 bool VisitBinGT(BinaryOperator const * expr);
93 bool VisitBinLE(BinaryOperator const * expr);
95 bool VisitBinGE(BinaryOperator const * expr);
97 bool VisitBinEQ(BinaryOperator const * expr);
99 bool VisitBinNE(BinaryOperator const * expr);
101 bool VisitConditionalOperator(ConditionalOperator const * expr);
104 void SimplifyBool::run() {
105 if (compiler.getLangOpts().CPlusPlus) {
106 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
110 bool SimplifyBool::VisitUnaryLNot(UnaryOperator const * expr) {
111 if (ignoreLocation(expr)) {
112 return true;
114 auto e = getSubExprOfLogicalNegation(expr->getSubExpr());
115 if (e) {
116 // Ignore macros, otherwise
117 // OSL_ENSURE(!b, ...);
118 // triggers.
119 if (e->getLocStart().isMacroID())
120 return true;
121 // double logical not of an int is an idiom to convert to bool
122 auto const sub = ignoreAllImplicit(e);
123 if (!sub->getType()->isBooleanType())
124 return true;
125 report(
126 DiagnosticsEngine::Warning,
127 ("double logical negation expression of the form '!!A' (with A of type"
128 " %0) can %select{logically|literally}1 be simplified as 'A'"),
129 expr->getLocStart())
130 << sub->getType()
131 << sub->getType()->isBooleanType()
132 << expr->getSourceRange();
133 return true;
135 if (auto binaryOp = dyn_cast<BinaryOperator>(expr->getSubExpr()->IgnoreParenImpCasts())) {
136 // Ignore macros, otherwise
137 // OSL_ENSURE(!b, ...);
138 // triggers.
139 if (binaryOp->getLocStart().isMacroID())
140 return true;
141 auto t = binaryOp->getLHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
142 // RecordType would require more smarts - we'd need to verify that an inverted operator actually existed
143 if (t->isTemplateTypeParmType() || t->isRecordType() || t->isDependentType())
144 return true;
145 // for floating point (with NaN) !(x<y) need not be equivalent to x>=y
146 if (t->isFloatingType() ||
147 binaryOp->getRHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType()->isFloatingType())
148 return true;
149 if (!binaryOp->isComparisonOp())
150 return true;
151 report(
152 DiagnosticsEngine::Warning,
153 ("logical negation of comparison operator, can be simplified by inverting operator"),
154 expr->getLocStart())
155 << expr->getSourceRange();
157 return true;
160 bool SimplifyBool::VisitBinLT(BinaryOperator const * expr) {
161 if (ignoreLocation(expr)) {
162 return true;
164 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
165 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
167 return true;
169 auto v1 = getValue(expr->getLHS());
170 auto v2 = getValue(expr->getRHS());
171 switch (v1) {
172 case Value::Unknown:
173 switch (v2) {
174 case Value::Unknown:
175 break;
176 case Value::False:
177 report(
178 DiagnosticsEngine::Warning,
179 ("less-than expression of the form 'A < false' (with A of type"
180 " %0) can logically be simplified as 'false'"),
181 expr->getLocStart())
182 << expr->getLHS()->IgnoreImpCasts()->getType()
183 << expr->getSourceRange();
184 break;
185 case Value::True:
187 auto e = getSubExprOfLogicalNegation(expr->getLHS());
188 if (e == nullptr) {
189 report(
190 DiagnosticsEngine::Warning,
191 ("less-than expression of the form 'A < true' (with A"
192 " of type %0) can %select{logically|literally}1 be"
193 " simplified as '!A'"),
194 expr->getLocStart())
195 << expr->getLHS()->IgnoreImpCasts()->getType()
196 << (expr->getLHS()->IgnoreImpCasts()->getType()
197 ->isBooleanType())
198 << expr->getSourceRange();
199 } else {
200 report(
201 DiagnosticsEngine::Warning,
202 ("less-than expression of the form '!A < true' (with A"
203 " of type %0) can %select{logically|literally}1 be"
204 " simplified as 'A'"),
205 expr->getLocStart())
206 << e->IgnoreImpCasts()->getType()
207 << e->IgnoreImpCasts()->getType()->isBooleanType()
208 << expr->getSourceRange();
210 break;
213 break;
214 case Value::False:
215 switch (v2) {
216 case Value::Unknown:
217 report(
218 DiagnosticsEngine::Warning,
219 ("less-than expression of the form 'false < A' (with A of type"
220 " %0) can %select{logically|literally}1 be simplified as 'A'"),
221 expr->getLocStart())
222 << expr->getRHS()->IgnoreImpCasts()->getType()
223 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
224 << expr->getSourceRange();
225 break;
226 case Value::False:
227 report(
228 DiagnosticsEngine::Warning,
229 ("less-than expression of the form 'false < false' can"
230 " literally be simplified as 'false'"),
231 expr->getLocStart())
232 << expr->getSourceRange();
233 break;
234 case Value::True:
235 report(
236 DiagnosticsEngine::Warning,
237 ("less-than expression of the form 'false < true' can"
238 " literally be simplified as 'true'"),
239 expr->getLocStart())
240 << expr->getSourceRange();
241 break;
243 break;
244 case Value::True:
245 switch (v2) {
246 case Value::Unknown:
247 report(
248 DiagnosticsEngine::Warning,
249 ("less-than expression of the form 'true < A' (with A of type"
250 " %0) can logically be simplified as 'false'"),
251 expr->getLocStart())
252 << expr->getRHS()->IgnoreImpCasts()->getType()
253 << expr->getSourceRange();
254 break;
255 case Value::False:
256 report(
257 DiagnosticsEngine::Warning,
258 ("less-than expression of the form 'true < false' can"
259 " literally be simplified as 'false'"),
260 expr->getLocStart())
261 << expr->getSourceRange();
262 break;
263 case Value::True:
264 report(
265 DiagnosticsEngine::Warning,
266 ("less-than expression of the form 'true < true' can"
267 " literally be simplified as 'false'"),
268 expr->getLocStart())
269 << expr->getSourceRange();
270 break;
272 break;
274 return true;
277 bool SimplifyBool::VisitBinGT(BinaryOperator const * expr) {
278 if (ignoreLocation(expr)) {
279 return true;
281 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
282 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
284 return true;
286 auto v1 = getValue(expr->getLHS());
287 auto v2 = getValue(expr->getRHS());
288 switch (v1) {
289 case Value::Unknown:
290 switch (v2) {
291 case Value::Unknown:
292 break;
293 case Value::False:
294 report(
295 DiagnosticsEngine::Warning,
296 ("greater-than expression of the form 'A > false' (with A of"
297 " type %0) can %select{logically|literally}1 be simplified as"
298 " 'A'"),
299 expr->getLocStart())
300 << expr->getLHS()->IgnoreImpCasts()->getType()
301 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
302 << expr->getSourceRange();
303 break;
304 case Value::True:
305 report(
306 DiagnosticsEngine::Warning,
307 ("greater-than expression of the form 'A > true' (with A of"
308 " type %0) can logically be simplified as 'false'"),
309 expr->getLocStart())
310 << expr->getLHS()->IgnoreImpCasts()->getType()
311 << expr->getSourceRange();
312 break;
314 break;
315 case Value::False:
316 switch (v2) {
317 case Value::Unknown:
318 report(
319 DiagnosticsEngine::Warning,
320 ("greater-than expression of the form 'false > A' (with A of"
321 " type %0) can logically be simplified as 'false'"),
322 expr->getLocStart())
323 << expr->getRHS()->IgnoreImpCasts()->getType()
324 << expr->getSourceRange();
325 break;
326 case Value::False:
327 report(
328 DiagnosticsEngine::Warning,
329 ("greater-than expression of the form 'false > false' can"
330 " literally be simplified as 'false'"),
331 expr->getLocStart())
332 << expr->getSourceRange();
333 break;
334 case Value::True:
335 report(
336 DiagnosticsEngine::Warning,
337 ("greater-than expression of the form 'false > true' can"
338 " literally be simplified as 'false'"),
339 expr->getLocStart())
340 << expr->getSourceRange();
341 break;
343 break;
344 case Value::True:
345 switch (v2) {
346 case Value::Unknown:
348 auto e = getSubExprOfLogicalNegation(expr->getRHS());
349 if (e == nullptr) {
350 report(
351 DiagnosticsEngine::Warning,
352 ("greater-than expression of the form 'true > A' (with"
353 " A of type %0) can %select{logically|literally}1 be"
354 " simplified as '!A'"),
355 expr->getLocStart())
356 << expr->getRHS()->IgnoreImpCasts()->getType()
357 << (expr->getRHS()->IgnoreImpCasts()->getType()
358 ->isBooleanType())
359 << expr->getSourceRange();
360 } else {
361 report(
362 DiagnosticsEngine::Warning,
363 ("greater-than expression of the form 'true > !A' (with"
364 " A of type %0) can %select{logically|literally}1 be"
365 " simplified as 'A'"),
366 expr->getLocStart())
367 << e->IgnoreImpCasts()->getType()
368 << e->IgnoreImpCasts()->getType()->isBooleanType()
369 << expr->getSourceRange();
371 break;
373 case Value::False:
374 report(
375 DiagnosticsEngine::Warning,
376 ("greater-than expression of the form 'true > false' can"
377 " literally be simplified as 'true'"),
378 expr->getLocStart())
379 << expr->getSourceRange();
380 break;
381 case Value::True:
382 report(
383 DiagnosticsEngine::Warning,
384 ("greater-than expression of the form 'true > true' can"
385 " literally be simplified as 'false'"),
386 expr->getLocStart())
387 << expr->getSourceRange();
388 break;
390 break;
392 return true;
395 bool SimplifyBool::VisitBinLE(BinaryOperator const * expr) {
396 if (ignoreLocation(expr)) {
397 return true;
399 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
400 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
402 return true;
404 auto v1 = getValue(expr->getLHS());
405 auto v2 = getValue(expr->getRHS());
406 switch (v1) {
407 case Value::Unknown:
408 switch (v2) {
409 case Value::Unknown:
410 break;
411 case Value::False:
413 auto e = getSubExprOfLogicalNegation(expr->getLHS());
414 if (e == nullptr) {
415 report(
416 DiagnosticsEngine::Warning,
417 ("less-than-or-equal-to expression of the form 'A <="
418 " false' (with A of type %0) can"
419 " %select{logically|literally}1 be simplified as"
420 " '!A'"),
421 expr->getLocStart())
422 << expr->getLHS()->IgnoreImpCasts()->getType()
423 << (expr->getLHS()->IgnoreImpCasts()->getType()
424 ->isBooleanType())
425 << expr->getSourceRange();
426 } else {
427 report(
428 DiagnosticsEngine::Warning,
429 ("less-than-or-equal-to expression of the form '!A <="
430 " false' (with A of type %0) can"
431 " %select{logically|literally}1 be simplified as 'A'"),
432 expr->getLocStart())
433 << e->IgnoreImpCasts()->getType()
434 << e->IgnoreImpCasts()->getType()->isBooleanType()
435 << expr->getSourceRange();
437 break;
439 case Value::True:
440 report(
441 DiagnosticsEngine::Warning,
442 ("less-than-or-equal-to expression of the form 'A <= true'"
443 " (with A of type %0) can logically be simplified as 'true'"),
444 expr->getLocStart())
445 << expr->getLHS()->IgnoreImpCasts()->getType()
446 << expr->getSourceRange();
447 break;
449 break;
450 case Value::False:
451 switch (v2) {
452 case Value::Unknown:
453 report(
454 DiagnosticsEngine::Warning,
455 ("less-than-or-equal-to expression of the form 'false <= A'"
456 " (with A of type %0) can logically be simplified as 'true'"),
457 expr->getLocStart())
458 << expr->getRHS()->IgnoreImpCasts()->getType()
459 << expr->getSourceRange();
460 break;
461 case Value::False:
462 report(
463 DiagnosticsEngine::Warning,
464 ("less-than-or-equal-to expression of the form 'false <= false'"
465 " can literally be simplified as 'true'"),
466 expr->getLocStart())
467 << expr->getSourceRange();
468 break;
469 case Value::True:
470 report(
471 DiagnosticsEngine::Warning,
472 ("less-than-or-equal-to expression of the form 'false <= true'"
473 " can literally be simplified as 'true'"),
474 expr->getLocStart())
475 << expr->getSourceRange();
476 break;
478 break;
479 case Value::True:
480 switch (v2) {
481 case Value::Unknown:
482 report(
483 DiagnosticsEngine::Warning,
484 ("less-than-or-equal-to expression of the form 'true <= A'"
485 " (with A of type %0) can %select{logically|literally}1 be"
486 " simplified as 'A'"),
487 expr->getLocStart())
488 << expr->getRHS()->IgnoreImpCasts()->getType()
489 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
490 << expr->getSourceRange();
491 break;
492 case Value::False:
493 report(
494 DiagnosticsEngine::Warning,
495 ("less-than-or-equal-to expression of the form 'true <= false'"
496 " can literally be simplified as 'false'"),
497 expr->getLocStart())
498 << expr->getSourceRange();
499 break;
500 case Value::True:
501 report(
502 DiagnosticsEngine::Warning,
503 ("less-than-or-equal-to expression of the form 'true <= true'"
504 " can literally be simplified as 'true'"),
505 expr->getLocStart())
506 << expr->getSourceRange();
507 break;
509 break;
511 return true;
514 bool SimplifyBool::VisitBinGE(BinaryOperator const * expr) {
515 if (ignoreLocation(expr)) {
516 return true;
518 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
519 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
521 return true;
523 auto v1 = getValue(expr->getLHS());
524 auto v2 = getValue(expr->getRHS());
525 switch (v1) {
526 case Value::Unknown:
527 switch (v2) {
528 case Value::Unknown:
529 break;
530 case Value::False:
531 report(
532 DiagnosticsEngine::Warning,
533 ("greater-than-or-equal-to expression of the form 'A >= false'"
534 " (with A of type %0) can logically be simplified as 'true'"),
535 expr->getLocStart())
536 << expr->getLHS()->IgnoreImpCasts()->getType()
537 << expr->getSourceRange();
538 break;
539 case Value::True:
540 report(
541 DiagnosticsEngine::Warning,
542 ("greater-than-or-equal-to expression of the form 'A >= true'"
543 " (with A of type %0) can %select{logically|literally}1 be"
544 " simplified as 'A'"),
545 expr->getLocStart())
546 << expr->getLHS()->IgnoreImpCasts()->getType()
547 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
548 << expr->getSourceRange();
549 break;
551 break;
552 case Value::False:
553 switch (v2) {
554 case Value::Unknown:
556 auto e = getSubExprOfLogicalNegation(expr->getRHS());
557 if (e == nullptr) {
558 report(
559 DiagnosticsEngine::Warning,
560 ("greater-than-or-equal-to expression of the form"
561 " 'false >= A' (with A of type %0) can"
562 " %select{logically|literally}1 be simplified as"
563 " '!A'"),
564 expr->getLocStart())
565 << expr->getRHS()->IgnoreImpCasts()->getType()
566 << (expr->getRHS()->IgnoreImpCasts()->getType()
567 ->isBooleanType())
568 << expr->getSourceRange();
569 } else {
570 report(
571 DiagnosticsEngine::Warning,
572 ("greater-than-or-equal-to expression of the form"
573 " 'false >= !A' (with A of type %0) can"
574 " %select{logically|literally}1 be simplified as 'A'"),
575 expr->getLocStart())
576 << e->IgnoreImpCasts()->getType()
577 << e->IgnoreImpCasts()->getType()->isBooleanType()
578 << expr->getSourceRange();
580 break;
582 case Value::False:
583 report(
584 DiagnosticsEngine::Warning,
585 ("greater-than-or-equal-to expression of the form 'false >="
586 " false' can literally be simplified as 'true'"),
587 expr->getLocStart())
588 << expr->getSourceRange();
589 break;
590 case Value::True:
591 report(
592 DiagnosticsEngine::Warning,
593 ("greater-than-or-equal-to expression of the form 'false >="
594 " true' can literally be simplified as 'false'"),
595 expr->getLocStart())
596 << expr->getSourceRange();
597 break;
599 break;
600 case Value::True:
601 switch (v2) {
602 case Value::Unknown:
603 report(
604 DiagnosticsEngine::Warning,
605 ("greater-than-or-equal-to expression of the form 'true >= A'"
606 " (with A of type %0) can logically be simplified as 'true'"),
607 expr->getLocStart())
608 << expr->getRHS()->IgnoreImpCasts()->getType()
609 << expr->getSourceRange();
610 break;
611 case Value::False:
612 report(
613 DiagnosticsEngine::Warning,
614 ("greater-than-or-equal-to expression of the form 'true >="
615 " false' can literally be simplified as 'true'"),
616 expr->getLocStart())
617 << expr->getSourceRange();
618 break;
619 case Value::True:
620 report(
621 DiagnosticsEngine::Warning,
622 ("greater-than-or-equal-to expression of the form 'true >="
623 " true' can literally be simplified as 'true'"),
624 expr->getLocStart())
625 << expr->getSourceRange();
626 break;
628 break;
630 return true;
633 bool SimplifyBool::VisitBinEQ(BinaryOperator const * expr) {
634 if (ignoreLocation(expr)) {
635 return true;
637 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
638 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
640 return true;
642 auto v1 = getValue(expr->getLHS());
643 auto v2 = getValue(expr->getRHS());
644 switch (v1) {
645 case Value::Unknown:
646 switch (v2) {
647 case Value::Unknown:
648 break;
649 case Value::False:
651 auto e = getSubExprOfLogicalNegation(expr->getLHS());
652 if (e == nullptr) {
653 report(
654 DiagnosticsEngine::Warning,
655 ("equal-to expression of the form 'A == false' (with A"
656 " of type %0) can %select{logically|literally}1 be"
657 " simplified as '!A'"),
658 expr->getLocStart())
659 << expr->getLHS()->IgnoreImpCasts()->getType()
660 << (expr->getLHS()->IgnoreImpCasts()->getType()
661 ->isBooleanType())
662 << expr->getSourceRange();
663 } else {
664 report(
665 DiagnosticsEngine::Warning,
666 ("equal-to expression of the form '!A == false' (with A"
667 " of type %0) can %select{logically|literally}1 be"
668 " simplified as 'A'"),
669 expr->getLocStart())
670 << e->IgnoreImpCasts()->getType()
671 << e->IgnoreImpCasts()->getType()->isBooleanType()
672 << expr->getSourceRange();
674 break;
676 case Value::True:
677 report(
678 DiagnosticsEngine::Warning,
679 ("equal-to expression of the form 'A == true' (with A of type"
680 " %0) can %select{logically|literally}1 be simplified as 'A'"),
681 expr->getLocStart())
682 << expr->getLHS()->IgnoreImpCasts()->getType()
683 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
684 << expr->getSourceRange();
685 break;
687 break;
688 case Value::False:
689 switch (v2) {
690 case Value::Unknown:
692 auto e = getSubExprOfLogicalNegation(expr->getRHS());
693 if (e == nullptr) {
694 report(
695 DiagnosticsEngine::Warning,
696 ("equal-to expression of the form 'false == A' (with A"
697 " of type %0) can %select{logically|literally}1 be"
698 " simplified as '!A'"),
699 expr->getLocStart())
700 << expr->getRHS()->IgnoreImpCasts()->getType()
701 << (expr->getRHS()->IgnoreImpCasts()->getType()
702 ->isBooleanType())
703 << expr->getSourceRange();
704 } else {
705 report(
706 DiagnosticsEngine::Warning,
707 ("equal-to expression of the form 'false == !A' (with A"
708 " of type %0) can %select{logically|literally}1 be"
709 " simplified as 'A'"),
710 expr->getLocStart())
711 << e->IgnoreImpCasts()->getType()
712 << e->IgnoreImpCasts()->getType()->isBooleanType()
713 << expr->getSourceRange();
715 break;
717 case Value::False:
718 report(
719 DiagnosticsEngine::Warning,
720 ("equal-to expression of the form 'false == false' can"
721 " literally be simplified as 'true'"),
722 expr->getLocStart())
723 << expr->getSourceRange();
724 break;
725 case Value::True:
726 report(
727 DiagnosticsEngine::Warning,
728 ("equal-to expression of the form 'false == true' can"
729 " literally be simplified as 'false'"),
730 expr->getLocStart())
731 << expr->getSourceRange();
732 break;
734 break;
735 case Value::True:
736 switch (v2) {
737 case Value::Unknown:
738 report(
739 DiagnosticsEngine::Warning,
740 ("equal-to expression of the form 'true == A' (with A of type"
741 " %0) can %select{logically|literally}1 be simplified as 'A'"),
742 expr->getLocStart())
743 << expr->getRHS()->IgnoreImpCasts()->getType()
744 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
745 << expr->getSourceRange();
746 break;
747 case Value::False:
748 report(
749 DiagnosticsEngine::Warning,
750 ("equal-to expression of the form 'true == false' can"
751 " literally be simplified as 'false'"),
752 expr->getLocStart())
753 << expr->getSourceRange();
754 break;
755 case Value::True:
756 report(
757 DiagnosticsEngine::Warning,
758 ("equal-to expression of the form 'true == true' can"
759 " literally be simplified as 'true'"),
760 expr->getLocStart())
761 << expr->getSourceRange();
762 break;
764 break;
766 return true;
769 bool SimplifyBool::VisitBinNE(BinaryOperator const * expr) {
770 if (ignoreLocation(expr)) {
771 return true;
773 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
774 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
776 return true;
778 auto v1 = getValue(expr->getLHS());
779 auto v2 = getValue(expr->getRHS());
780 switch (v1) {
781 case Value::Unknown:
782 switch (v2) {
783 case Value::Unknown:
784 break;
785 case Value::False:
786 report(
787 DiagnosticsEngine::Warning,
788 ("not-equal-to expression of the form 'A != false' (with A of"
789 " type %0) can %select{logically|literally}1 be simplified as"
790 " 'A'"),
791 expr->getLocStart())
792 << expr->getLHS()->IgnoreImpCasts()->getType()
793 << expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
794 << expr->getSourceRange();
795 break;
796 case Value::True:
798 auto e = getSubExprOfLogicalNegation(expr->getLHS());
799 if (e == nullptr) {
800 report(
801 DiagnosticsEngine::Warning,
802 ("not-equal-to expression of the form 'A != true' (with"
803 " A of type %0) can %select{logically|literally}1 be"
804 " simplified as '!A'"),
805 expr->getLocStart())
806 << expr->getLHS()->IgnoreImpCasts()->getType()
807 << (expr->getLHS()->IgnoreImpCasts()->getType()
808 ->isBooleanType())
809 << expr->getSourceRange();
810 } else {
811 report(
812 DiagnosticsEngine::Warning,
813 ("not-equal-to expression of the form '!A != true'"
814 " (with A of type %0) can"
815 " %select{logically|literally}1 be simplified as 'A'"),
816 expr->getLocStart())
817 << e->IgnoreImpCasts()->getType()
818 << e->IgnoreImpCasts()->getType()->isBooleanType()
819 << expr->getSourceRange();
821 break;
824 break;
825 case Value::False:
826 switch (v2) {
827 case Value::Unknown:
828 report(
829 DiagnosticsEngine::Warning,
830 ("not-equal-to expression of the form 'false != A' (with A of"
831 " type %0) can %select{logically|literally}1 be simplified as"
832 " 'A'"),
833 expr->getLocStart())
834 << expr->getRHS()->IgnoreImpCasts()->getType()
835 << expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
836 << expr->getSourceRange();
837 break;
838 case Value::False:
839 report(
840 DiagnosticsEngine::Warning,
841 ("not-equal-to expression of the form 'false != false' can"
842 " literally be simplified as 'false'"),
843 expr->getLocStart())
844 << expr->getSourceRange();
845 break;
846 case Value::True:
847 report(
848 DiagnosticsEngine::Warning,
849 ("not-equal-to expression of the form 'false != true' can"
850 " literally be simplified as 'true'"),
851 expr->getLocStart())
852 << expr->getSourceRange();
853 break;
855 break;
856 case Value::True:
857 switch (v2) {
858 case Value::Unknown:
860 auto e = getSubExprOfLogicalNegation(expr->getRHS());
861 if (e == nullptr) {
862 report(
863 DiagnosticsEngine::Warning,
864 ("not-equal-to expression of the form 'true != A' (with"
865 " A of type %0) can %select{logically|literally}1 be"
866 " simplified as '!A'"),
867 expr->getLocStart())
868 << expr->getRHS()->IgnoreImpCasts()->getType()
869 << (expr->getRHS()->IgnoreImpCasts()->getType()
870 ->isBooleanType())
871 << expr->getSourceRange();
872 } else {
873 report(
874 DiagnosticsEngine::Warning,
875 ("not-equal-to expression of the form 'true != !A'"
876 " (with A of type %0) can"
877 " %select{logically|literally}1 be simplified as 'A'"),
878 expr->getLocStart())
879 << e->IgnoreImpCasts()->getType()
880 << e->IgnoreImpCasts()->getType()->isBooleanType()
881 << expr->getSourceRange();
883 break;
885 case Value::False:
886 report(
887 DiagnosticsEngine::Warning,
888 ("not-equal-to expression of the form 'true != false' can"
889 " literally be simplified as 'true'"),
890 expr->getLocStart())
891 << expr->getSourceRange();
892 break;
893 case Value::True:
894 report(
895 DiagnosticsEngine::Warning,
896 ("not-equal-to expression of the form 'true != true' can"
897 " literally be simplified as 'false'"),
898 expr->getLocStart())
899 << expr->getSourceRange();
900 break;
902 break;
904 return true;
907 bool SimplifyBool::VisitConditionalOperator(ConditionalOperator const * expr) {
908 if (ignoreLocation(expr)) {
909 return true;
911 auto v1 = getValue(expr->getTrueExpr());
912 auto v2 = getValue(expr->getFalseExpr());
913 switch (v1) {
914 case Value::Unknown:
915 switch (v2) {
916 case Value::Unknown:
917 break;
918 case Value::False:
919 report(
920 DiagnosticsEngine::Warning,
921 ("conditional expression of the form 'A ? B : false' (with A of"
922 " type %0 and B of type %1) can %select{logically|literally}2"
923 " be simplified as 'A && B'"),
924 expr->getLocStart())
925 << expr->getCond()->IgnoreImpCasts()->getType()
926 << expr->getTrueExpr()->IgnoreImpCasts()->getType()
927 << ((expr->getCond()->IgnoreImpCasts()->getType()
928 ->isBooleanType())
929 && (expr->getTrueExpr()->IgnoreImpCasts()->getType()
930 ->isBooleanType()))
931 << expr->getSourceRange();
932 break;
933 case Value::True:
935 auto e = getSubExprOfLogicalNegation(expr->getCond());
936 if (e == nullptr) {
937 report(
938 DiagnosticsEngine::Warning,
939 ("conditional expression of the form 'A ? B : true'"
940 " (with A of type %0 and B of type %1) can"
941 " %select{logically|literally}2 be simplified as '!A"
942 " || B'"),
943 expr->getLocStart())
944 << expr->getCond()->IgnoreImpCasts()->getType()
945 << expr->getTrueExpr()->IgnoreImpCasts()->getType()
946 << ((expr->getCond()->IgnoreImpCasts()->getType()
947 ->isBooleanType())
948 && (expr->getTrueExpr()->IgnoreImpCasts()->getType()
949 ->isBooleanType()))
950 << expr->getSourceRange();
951 } else {
952 report(
953 DiagnosticsEngine::Warning,
954 ("conditional expression of the form '!A ? B : true'"
955 " (with A of type %0 and B of type %1) can"
956 " %select{logically|literally}2 be simplified as 'A ||"
957 " B'"),
958 expr->getLocStart())
959 << e->IgnoreImpCasts()->getType()
960 << expr->getTrueExpr()->IgnoreImpCasts()->getType()
961 << (e->IgnoreImpCasts()->getType()->isBooleanType()
962 && (expr->getTrueExpr()->IgnoreImpCasts()
963 ->getType()->isBooleanType()))
964 << expr->getSourceRange();
966 break;
969 break;
970 case Value::False:
971 switch (v2) {
972 case Value::Unknown:
974 auto e = getSubExprOfLogicalNegation(expr->getCond());
975 if (e == nullptr) {
976 report(
977 DiagnosticsEngine::Warning,
978 ("conditional expression of the form 'A ? false : B'"
979 " (with A of type %0 and B of type %1) can"
980 " %select{logically|literally}2 be simplified as '!A"
981 " && B'"),
982 expr->getLocStart())
983 << expr->getCond()->IgnoreImpCasts()->getType()
984 << expr->getFalseExpr()->IgnoreImpCasts()->getType()
985 << ((expr->getCond()->IgnoreImpCasts()->getType()
986 ->isBooleanType())
987 && (expr->getFalseExpr()->IgnoreImpCasts()
988 ->getType()->isBooleanType()))
989 << expr->getSourceRange();
990 } else {
991 report(
992 DiagnosticsEngine::Warning,
993 ("conditional expression of the form '!A ? false : B'"
994 " (with A of type %0 and B of type %1) can"
995 " %select{logically|literally}2 be simplified as 'A &&"
996 " B'"),
997 expr->getLocStart())
998 << e->IgnoreImpCasts()->getType()
999 << expr->getFalseExpr()->IgnoreImpCasts()->getType()
1000 << (e->IgnoreImpCasts()->getType()->isBooleanType()
1001 && (expr->getFalseExpr()->IgnoreImpCasts()
1002 ->getType()->isBooleanType()))
1003 << expr->getSourceRange();
1005 break;
1007 case Value::False:
1008 report(
1009 DiagnosticsEngine::Warning,
1010 ("conditional expression of the form 'A ? false : false' (with"
1011 " A of type %0) can logically be simplified as 'false'"),
1012 expr->getLocStart())
1013 << expr->getCond()->IgnoreImpCasts()->getType()
1014 << expr->getSourceRange();
1015 break;
1016 case Value::True:
1018 auto e = getSubExprOfLogicalNegation(expr->getCond());
1019 if (e == nullptr) {
1020 report(
1021 DiagnosticsEngine::Warning,
1022 ("conditional expression of the form 'A ? false : true'"
1023 " (with A of type %0) can"
1024 " %select{logically|literally}1 be simplified as"
1025 " '!A'"),
1026 expr->getLocStart())
1027 << expr->getCond()->IgnoreImpCasts()->getType()
1028 << (expr->getCond()->IgnoreImpCasts()->getType()
1029 ->isBooleanType())
1030 << expr->getSourceRange();
1031 } else {
1032 report(
1033 DiagnosticsEngine::Warning,
1034 ("conditional expression of the form '!A ? false :"
1035 " true' (with A of type %0) can"
1036 " %select{logically|literally}1 be simplified as 'A'"),
1037 expr->getLocStart())
1038 << e->IgnoreImpCasts()->getType()
1039 << e->IgnoreImpCasts()->getType()->isBooleanType()
1040 << expr->getSourceRange();
1042 break;
1045 break;
1046 case Value::True:
1047 switch (v2) {
1048 case Value::Unknown:
1049 report(
1050 DiagnosticsEngine::Warning,
1051 ("conditional expression of the form 'A ? true : B' (with A of"
1052 " type %0 and B of type %1) can %select{logically|literally}2"
1053 " be simplified as 'A || B'"),
1054 expr->getLocStart())
1055 << expr->getCond()->IgnoreImpCasts()->getType()
1056 << expr->getFalseExpr()->IgnoreImpCasts()->getType()
1057 << ((expr->getCond()->IgnoreImpCasts()->getType()
1058 ->isBooleanType())
1059 && (expr->getFalseExpr()->IgnoreImpCasts()->getType()
1060 ->isBooleanType()))
1061 << expr->getSourceRange();
1062 break;
1063 case Value::False:
1064 report(
1065 DiagnosticsEngine::Warning,
1066 ("conditional expression of the form 'A ? true : false' (with A"
1067 " of type %0) can %select{logically|literally}1 be simplified"
1068 " as 'A'"),
1069 expr->getLocStart())
1070 << expr->getCond()->IgnoreImpCasts()->getType()
1071 << expr->getCond()->IgnoreImpCasts()->getType()->isBooleanType()
1072 << expr->getSourceRange();
1073 break;
1074 case Value::True:
1075 report(
1076 DiagnosticsEngine::Warning,
1077 ("conditional expression of the form 'A ? true : true' (with A"
1078 " of type %0) can logically be simplified as 'true'"),
1079 expr->getLocStart())
1080 << expr->getCond()->IgnoreImpCasts()->getType()
1081 << expr->getSourceRange();
1082 break;
1084 break;
1086 return true;
1089 loplugin::Plugin::Registration<SimplifyBool> X("simplifybool");
1093 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */