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