1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
14 #include "clang/AST/CXXInheritance.h"
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();
41 Expr
const * ignoreParenImpCastAndComma(Expr
const * expr
) {
43 expr
= expr
->IgnoreParenImpCasts();
44 auto e
= dyn_cast
<BinaryOperator
>(expr
);
45 if (e
== nullptr || e
->getOpcode() != BO_Comma
) {
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
);
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
);
70 CXXRecordDecl
const * paramRecordDecl
= dyn_cast
<CXXRecordDecl
>(paramRecordType
->getDecl());
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
))
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
);
96 auto rhsRecordType
= dyn_cast
<RecordType
>(rhsType
);
99 CXXRecordDecl
const * lhsRecordDecl
= dyn_cast
<CXXRecordDecl
>(lhsRecordType
->getDecl());
102 CXXRecordDecl
const * rhsRecordDecl
= dyn_cast
<CXXRecordDecl
>(rhsRecordType
->getDecl());
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
);
127 return foundFunction
;
128 auto ForallBasesCallback
= [&](const CXXRecordDecl
*baseCXXRecordDecl
)
130 if (baseCXXRecordDecl
->isInvalidDecl())
132 foundFunction
= findMemberOperator(baseCXXRecordDecl
, ooOpcode
, rhsRecordDecl
);
136 lhsRecordDecl
->forallBases(ForallBasesCallback
);
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)
150 if (!isCompatibleTypeForOperator(f
->getParamDecl(0)->getType().getTypePtr(), lhsRecordDecl
))
152 if (!isCompatibleTypeForOperator(f
->getParamDecl(1)->getType().getTypePtr(), rhsRecordDecl
))
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;
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
;
182 public loplugin::FilteringPlugin
<SimplifyBool
>
185 explicit SimplifyBool(loplugin::InstantiationData
const & data
):
186 FilteringPlugin(data
) {}
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
*);
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
) {
226 if (ignoreLocation(expr
)) {
229 auto e
= getSubExprOfLogicalNegation(expr
->getSubExpr());
231 // Ignore macros, otherwise
232 // OSL_ENSURE(!b, ...);
234 if (compat::getBeginLoc(e
).isMacroID())
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())
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
))
246 << sub
->getType()->isBooleanType()
247 << expr
->getSourceRange();
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();
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
;
273 if (auto binaryOp
= dyn_cast
<BinaryOperator
>(sub
)) {
274 // Ignore macros, otherwise
275 // OSL_ENSURE(!b, ...);
277 if (compat::getBeginLoc(binaryOp
).isMacroID())
279 if (binaryOp
->isComparisonOp())
281 auto t
= binaryOp
->getLHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
282 if (t
->isTemplateTypeParmType() || t
->isDependentType() || t
->isRecordType())
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())
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
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
)
307 if (auto binaryOp
= dyn_cast
<BinaryOperator
>(expr
))
308 if (binaryOp
->isComparisonOp())
310 if (auto cxxOpCall
= dyn_cast
<CXXOperatorCallExpr
>(expr
))
311 if (compat::isComparisonOp(cxxOpCall
))
313 return (Expr
const*)nullptr;
315 auto lhs
= containsNegationOrComparison(binaryOp
->getLHS());
316 auto rhs
= containsNegationOrComparison(binaryOp
->getRHS());
317 if (foundLNot
|| (lhs
&& rhs
))
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, ...);
329 if (compat::getBeginLoc(binaryOp
).isMacroID())
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
))
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
);
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());
349 StringRef
fn(handler
.getMainFileName());
350 if (loplugin::isSamePathname(fn
, SRCDIR
"/testtools/source/bridgetest/bridgetest.cxx"))
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
)
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();
368 bool SimplifyBool::VisitBinaryOperator(BinaryOperator
const * expr
) {
369 switch (expr
->getOpcode()) {
371 return visitBinLT(expr
);
373 return visitBinGT(expr
);
375 return visitBinLE(expr
);
377 return visitBinGE(expr
);
379 return visitBinEQ(expr
);
381 return visitBinNE(expr
);
387 bool SimplifyBool::visitBinLT(BinaryOperator
const * expr
) {
388 if (ignoreLocation(expr
)) {
391 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
392 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
396 auto v1
= getValue(expr
->getLHS());
397 auto v2
= getValue(expr
->getRHS());
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();
414 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
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()
425 << expr
->getSourceRange();
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();
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();
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();
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();
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();
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();
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();
504 bool SimplifyBool::visitBinGT(BinaryOperator
const * expr
) {
505 if (ignoreLocation(expr
)) {
508 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
509 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
513 auto v1
= getValue(expr
->getLHS());
514 auto v2
= getValue(expr
->getRHS());
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"
526 compat::getBeginLoc(expr
))
527 << expr
->getLHS()->IgnoreImpCasts()->getType()
528 << expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
529 << expr
->getSourceRange();
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();
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();
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();
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();
575 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
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()
586 << expr
->getSourceRange();
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();
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();
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();
622 bool SimplifyBool::visitBinLE(BinaryOperator
const * expr
) {
623 if (ignoreLocation(expr
)) {
626 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
627 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
631 auto v1
= getValue(expr
->getLHS());
632 auto v2
= getValue(expr
->getRHS());
640 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
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"
648 compat::getBeginLoc(expr
))
649 << expr
->getLHS()->IgnoreImpCasts()->getType()
650 << (expr
->getLHS()->IgnoreImpCasts()->getType()
652 << expr
->getSourceRange();
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();
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();
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();
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();
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();
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();
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();
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();
741 bool SimplifyBool::visitBinGE(BinaryOperator
const * expr
) {
742 if (ignoreLocation(expr
)) {
745 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
746 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
750 auto v1
= getValue(expr
->getLHS());
751 auto v2
= getValue(expr
->getRHS());
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();
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();
783 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
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"
791 compat::getBeginLoc(expr
))
792 << expr
->getRHS()->IgnoreImpCasts()->getType()
793 << (expr
->getRHS()->IgnoreImpCasts()->getType()
795 << expr
->getSourceRange();
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();
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();
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();
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();
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();
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();
860 bool SimplifyBool::visitBinEQ(BinaryOperator
const * expr
) {
861 if (ignoreLocation(expr
)) {
864 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
865 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
869 auto v1
= getValue(expr
->getLHS());
870 auto v2
= getValue(expr
->getRHS());
878 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
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()
889 << expr
->getSourceRange();
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();
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();
919 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
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()
930 << expr
->getSourceRange();
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();
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();
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();
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();
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();
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();
996 bool SimplifyBool::visitBinNE(BinaryOperator
const * expr
) {
997 if (ignoreLocation(expr
)) {
1000 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
1001 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
1005 auto v1
= getValue(expr
->getLHS());
1006 auto v2
= getValue(expr
->getRHS());
1008 case Value::Unknown
:
1010 case Value::Unknown
:
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"
1018 compat::getBeginLoc(expr
))
1019 << expr
->getLHS()->IgnoreImpCasts()->getType()
1020 << expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
1021 << expr
->getSourceRange();
1025 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
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()
1036 << expr
->getSourceRange();
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();
1054 case Value::Unknown
:
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"
1060 compat::getBeginLoc(expr
))
1061 << expr
->getRHS()->IgnoreImpCasts()->getType()
1062 << expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
1063 << expr
->getSourceRange();
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();
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();
1085 case Value::Unknown
:
1087 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
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()
1098 << expr
->getSourceRange();
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();
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();
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();
1134 bool SimplifyBool::VisitConditionalOperator(ConditionalOperator
const * expr
) {
1135 if (ignoreLocation(expr
)) {
1138 auto v1
= getValue(expr
->getTrueExpr());
1139 auto v2
= getValue(expr
->getFalseExpr());
1141 case Value::Unknown
:
1143 case Value::Unknown
:
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()
1156 && (expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1158 << expr
->getSourceRange();
1162 auto e
= getSubExprOfLogicalNegation(expr
->getCond());
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"
1170 compat::getBeginLoc(expr
))
1171 << expr
->getCond()->IgnoreImpCasts()->getType()
1172 << expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1173 << ((expr
->getCond()->IgnoreImpCasts()->getType()
1175 && (expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1177 << expr
->getSourceRange();
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 ||"
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();
1199 case Value::Unknown
:
1201 auto e
= getSubExprOfLogicalNegation(expr
->getCond());
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"
1209 compat::getBeginLoc(expr
))
1210 << expr
->getCond()->IgnoreImpCasts()->getType()
1211 << expr
->getFalseExpr()->IgnoreImpCasts()->getType()
1212 << ((expr
->getCond()->IgnoreImpCasts()->getType()
1214 && (expr
->getFalseExpr()->IgnoreImpCasts()
1215 ->getType()->isBooleanType()))
1216 << expr
->getSourceRange();
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 &&"
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();
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();
1245 auto e
= getSubExprOfLogicalNegation(expr
->getCond());
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"
1253 compat::getBeginLoc(expr
))
1254 << expr
->getCond()->IgnoreImpCasts()->getType()
1255 << (expr
->getCond()->IgnoreImpCasts()->getType()
1257 << expr
->getSourceRange();
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();
1275 case Value::Unknown
:
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()
1286 && (expr
->getFalseExpr()->IgnoreImpCasts()->getType()
1288 << expr
->getSourceRange();
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"
1296 compat::getBeginLoc(expr
))
1297 << expr
->getCond()->IgnoreImpCasts()->getType()
1298 << expr
->getCond()->IgnoreImpCasts()->getType()->isBooleanType()
1299 << expr
->getSourceRange();
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();
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
;
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
;
1332 loplugin::Plugin::Registration
<SimplifyBool
> X("simplifybool");
1336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */