nss: upgrade to release 3.73
[LibreOffice.git] / compilerplugins / clang / simplifybool.cxx
blobd2e53d63aae979bf83f66a27f9735da22e592672
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 "compat.hxx"
13 #include "plugin.hxx"
14 #include "clang/AST/CXXInheritance.h"
16 namespace {
18 // Like clang::Stmt::IgnoreImplicit (lib/AST/Stmt.cpp), but also looking through implicit
19 // UserDefinedConversion's member function call:
20 Expr const * ignoreAllImplicit(Expr const * expr) {
21 if (auto const e = dyn_cast<ExprWithCleanups>(expr)) {
22 expr = e->getSubExpr();
24 if (auto const e = dyn_cast<MaterializeTemporaryExpr>(expr)) {
25 expr = compat::getSubExpr(e);
27 if (auto const e = dyn_cast<CXXBindTemporaryExpr>(expr)) {
28 expr = e->getSubExpr();
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();
38 return 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;
48 expr = e->getRHS();
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();
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();
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);
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;
83 return nullptr;
86 // Magic value to indicate we assume this operator exists
87 static FunctionDecl const * const ASSUME_OPERATOR_EXISTS = reinterpret_cast<FunctionDecl const *>(-1);
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:
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;
106 auto ctx = lhsRecordDecl->getCanonicalDecl()->getDeclContext();
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.
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;
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)
130 if (baseCXXRecordDecl->isInvalidDecl())
131 return false;
132 foundFunction = findMemberOperator(baseCXXRecordDecl, ooOpcode, rhsRecordDecl);
133 return false;
136 lhsRecordDecl->forallBases(ForallBasesCallback);
137 if (foundFunction)
138 return foundFunction;
140 // search for free function overloads
141 if (ctx->getDeclKind() == Decl::LinkageSpec) {
142 ctx = ctx->getParent();
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;
156 return nullptr;
159 enum class Value { Unknown, False, True };
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
167 // const bool DIAG_DBL_CLIP_DEFAULT = false;
168 // ...
169 // ... = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
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;
178 return Value::Unknown;
181 class SimplifyBool:
182 public loplugin::FilteringPlugin<SimplifyBool>
184 public:
185 explicit SimplifyBool(loplugin::InstantiationData const & data):
186 FilteringPlugin(data) {}
188 void run() override;
190 bool VisitUnaryOperator(UnaryOperator const * expr);
192 bool VisitBinaryOperator(BinaryOperator const * expr);
194 bool VisitConditionalOperator(ConditionalOperator const * expr);
196 bool TraverseFunctionDecl(FunctionDecl *);
198 bool TraverseCXXMethodDecl(CXXMethodDecl *);
200 private:
201 bool visitBinLT(BinaryOperator const * expr);
203 bool visitBinGT(BinaryOperator const * expr);
205 bool visitBinLE(BinaryOperator const * expr);
207 bool visitBinGE(BinaryOperator const * expr);
209 bool visitBinEQ(BinaryOperator const * expr);
211 bool visitBinNE(BinaryOperator const * expr);
213 FunctionDecl* m_insideFunctionDecl = nullptr;
216 void SimplifyBool::run() {
217 if (compiler.getLangOpts().CPlusPlus) {
218 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
222 bool SimplifyBool::VisitUnaryOperator(UnaryOperator const * expr) {
223 if (expr->getOpcode() != UO_LNot) {
224 return true;
226 if (ignoreLocation(expr)) {
227 return true;
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;
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;
265 if (match) {
266 sub = sem;
267 reversed = true;
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())
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();
294 else if (binaryOp->isLogicalOp())
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)
304 foundLNot = true;
305 return expr;
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;
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();
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;
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();
365 return true;
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;
387 bool SimplifyBool::visitBinLT(BinaryOperator const * expr) {
388 if (ignoreLocation(expr)) {
389 return true;
391 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
392 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
394 return true;
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:
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();
437 break;
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;
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;
499 break;
501 return true;
504 bool SimplifyBool::visitBinGT(BinaryOperator const * expr) {
505 if (ignoreLocation(expr)) {
506 return true;
508 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
509 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
511 return true;
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;
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;
570 break;
571 case Value::True:
572 switch (v2) {
573 case Value::Unknown:
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();
598 break;
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;
617 break;
619 return true;
622 bool SimplifyBool::visitBinLE(BinaryOperator const * expr) {
623 if (ignoreLocation(expr)) {
624 return true;
626 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
627 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
629 return true;
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:
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();
664 break;
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;
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;
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;
736 break;
738 return true;
741 bool SimplifyBool::visitBinGE(BinaryOperator const * expr) {
742 if (ignoreLocation(expr)) {
743 return true;
745 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
746 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
748 return true;
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;
778 break;
779 case Value::False:
780 switch (v2) {
781 case Value::Unknown:
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();
807 break;
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;
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;
855 break;
857 return true;
860 bool SimplifyBool::visitBinEQ(BinaryOperator const * expr) {
861 if (ignoreLocation(expr)) {
862 return true;
864 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
865 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
867 return true;
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:
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();
901 break;
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;
914 break;
915 case Value::False:
916 switch (v2) {
917 case Value::Unknown:
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();
942 break;
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;
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;
991 break;
993 return true;
996 bool SimplifyBool::visitBinNE(BinaryOperator const * expr) {
997 if (ignoreLocation(expr)) {
998 return true;
1000 if (!(expr->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
1001 && expr->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
1003 return true;
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:
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();
1048 break;
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;
1082 break;
1083 case Value::True:
1084 switch (v2) {
1085 case Value::Unknown:
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();
1110 break;
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;
1129 break;
1131 return true;
1134 bool SimplifyBool::VisitConditionalOperator(ConditionalOperator const * expr) {
1135 if (ignoreLocation(expr)) {
1136 return true;
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:
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();
1193 break;
1196 break;
1197 case Value::False:
1198 switch (v2) {
1199 case Value::Unknown:
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();
1232 break;
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:
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();
1269 break;
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;
1311 break;
1313 return true;
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;
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;
1332 loplugin::Plugin::Registration<SimplifyBool> X("simplifybool");
1336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */