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/.
13 #include "clang/AST/CXXInheritance.h"
17 // Like clang::Stmt::IgnoreImplicit (lib/AST/Stmt.cpp), but also looking through implicit
18 // UserDefinedConversion's member function call:
19 Expr
const * ignoreAllImplicit(Expr
const * expr
) {
20 if (auto const e
= dyn_cast
<ExprWithCleanups
>(expr
)) {
21 expr
= e
->getSubExpr();
23 if (auto const e
= dyn_cast
<MaterializeTemporaryExpr
>(expr
)) {
24 expr
= e
->getSubExpr();
26 if (auto const e
= dyn_cast
<CXXBindTemporaryExpr
>(expr
)) {
27 expr
= e
->getSubExpr();
29 while (auto const e
= dyn_cast
<ImplicitCastExpr
>(expr
)) {
30 expr
= e
->getSubExpr();
31 if (e
->getCastKind() == CK_UserDefinedConversion
) {
32 auto const ce
= cast
<CXXMemberCallExpr
>(expr
);
33 assert(ce
->getNumArgs() == 0);
34 expr
= ce
->getImplicitObjectArgument();
40 Expr
const * ignoreParenImpCastAndComma(Expr
const * expr
) {
42 expr
= expr
->IgnoreParenImpCasts();
43 auto e
= dyn_cast
<BinaryOperator
>(expr
);
44 if (e
== nullptr || e
->getOpcode() != BO_Comma
) {
51 Expr
const * getSubExprOfLogicalNegation(Expr
const * expr
) {
52 auto e
= dyn_cast
<UnaryOperator
>(ignoreParenImpCastAndComma(expr
));
53 return e
== nullptr || e
->getOpcode() != UO_LNot
54 ? nullptr : e
->getSubExpr();
57 clang::Type
const * stripConstRef(clang::Type
const * type
) {
58 auto lvalueType
= dyn_cast
<LValueReferenceType
>(type
);
61 return lvalueType
->getPointeeType()->getUnqualifiedDesugaredType();
64 bool isCompatibleTypeForOperator(clang::Type
const * paramType
, CXXRecordDecl
const * argRecordDecl
) {
65 paramType
= stripConstRef(paramType
);
66 auto paramRecordType
= dyn_cast
<RecordType
>(paramType
);
69 CXXRecordDecl
const * paramRecordDecl
= dyn_cast
<CXXRecordDecl
>(paramRecordType
->getDecl());
72 return argRecordDecl
== paramRecordDecl
|| argRecordDecl
->isDerivedFrom(paramRecordDecl
);
75 FunctionDecl
const * findMemberOperator(CXXRecordDecl
const * recordDecl
, OverloadedOperatorKind ooOpcode
, CXXRecordDecl
const * rhs
) {
76 for (auto it
= recordDecl
->method_begin(); it
!= recordDecl
->method_end(); ++it
) {
77 if (it
->getOverloadedOperator() == ooOpcode
) {
78 if (it
->getNumParams() == 1 && isCompatibleTypeForOperator(it
->getParamDecl(0)->getType().getTypePtr(), rhs
))
85 // Magic value to indicate we assume this operator exists
86 static FunctionDecl
const * const ASSUME_OPERATOR_EXISTS
= reinterpret_cast<FunctionDecl
const *>(-1);
88 // Search for an operator with matching parameter types; while this may miss some operators with
89 // odd parameter types that would actually be used by the compiler, it is overall better to have too
90 // many false negatives (i.e., miss valid loplugin:simplifybool warnings) than false positives here:
91 FunctionDecl
const * findOperator(CompilerInstance
& compiler
, BinaryOperator::Opcode opcode
, clang::Type
const * lhsType
, clang::Type
const * rhsType
) {
92 auto lhsRecordType
= dyn_cast
<RecordType
>(lhsType
);
95 auto rhsRecordType
= dyn_cast
<RecordType
>(rhsType
);
98 CXXRecordDecl
const * lhsRecordDecl
= dyn_cast
<CXXRecordDecl
>(lhsRecordType
->getDecl());
101 CXXRecordDecl
const * rhsRecordDecl
= dyn_cast
<CXXRecordDecl
>(rhsRecordType
->getDecl());
105 auto ctx
= lhsRecordDecl
->getCanonicalDecl()->getDeclContext();
108 It looks the clang Sema::LookupOverloadedOperatorName is the chunk of functionality I need,
109 but I have no idea how to call it from here.
110 Actually finding the right standard library operators requires doing conversions and other funky stuff.
111 For now, just assume that standard library operators are well-behaved, and have negated operators.
113 if (ctx
->isStdNamespace())
114 return ASSUME_OPERATOR_EXISTS
;
115 if (auto namespaceDecl
= dyn_cast
<NamespaceDecl
>(ctx
)) {
116 // because, of course, half the standard library is not "in the standard namespace"
117 if (namespaceDecl
->getName() == "__gnu_debug")
118 return ASSUME_OPERATOR_EXISTS
;
121 // search for member overloads
122 // (using the hard way here because DeclContext::lookup does not work for member operators)
123 auto ooOpcode
= BinaryOperator::getOverloadedOperator(opcode
);
124 FunctionDecl
const * foundFunction
= findMemberOperator(lhsRecordDecl
, ooOpcode
, rhsRecordDecl
);
126 return foundFunction
;
127 auto ForallBasesCallback
= [&](const CXXRecordDecl
*baseCXXRecordDecl
)
129 if (baseCXXRecordDecl
->isInvalidDecl())
131 foundFunction
= findMemberOperator(baseCXXRecordDecl
, ooOpcode
, rhsRecordDecl
);
135 lhsRecordDecl
->forallBases(ForallBasesCallback
);
137 return foundFunction
;
139 // search for free function overloads
140 if (ctx
->getDeclKind() == Decl::LinkageSpec
) {
141 ctx
= ctx
->getParent();
143 auto operatorDeclName
= compiler
.getASTContext().DeclarationNames
.getCXXOperatorName(ooOpcode
);
144 auto res
= ctx
->lookup(operatorDeclName
);
145 for (auto d
= res
.begin(); d
!= res
.end(); ++d
) {
146 FunctionDecl
const * f
= dyn_cast
<FunctionDecl
>(*d
);
147 if (!f
|| f
->getNumParams() != 2)
149 if (!isCompatibleTypeForOperator(f
->getParamDecl(0)->getType().getTypePtr(), lhsRecordDecl
))
151 if (!isCompatibleTypeForOperator(f
->getParamDecl(1)->getType().getTypePtr(), rhsRecordDecl
))
158 enum class Value
{ Unknown
, False
, True
};
160 Value
getValue(Expr
const * expr
) {
161 expr
= ignoreParenImpCastAndComma(expr
);
162 if (expr
->getType()->isBooleanType()) {
163 // Instead going via Expr::isCXX11ConstantExpr would turn up exactly one
164 // additional place in svx/source/dialog/framelinkarray.cxx
166 // const bool DIAG_DBL_CLIP_DEFAULT = false;
168 // ... = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
170 // where it is unclear whether it is not actually better to consider
171 // DIAG_DBL_CLIP_DEFAULT a tunable parameter (and thus not to simplify):
172 auto lit
= dyn_cast
<CXXBoolLiteralExpr
>(expr
);
173 if (lit
!= nullptr) {
174 return lit
->getValue() ? Value::True
: Value::False
;
177 return Value::Unknown
;
181 public loplugin::FilteringPlugin
<SimplifyBool
>
184 explicit SimplifyBool(loplugin::InstantiationData
const & data
):
185 FilteringPlugin(data
) {}
189 bool VisitUnaryOperator(UnaryOperator
const * expr
);
191 bool VisitBinaryOperator(BinaryOperator
const * expr
);
193 bool VisitConditionalOperator(ConditionalOperator
const * expr
);
195 bool TraverseFunctionDecl(FunctionDecl
*);
197 bool TraverseCXXMethodDecl(CXXMethodDecl
*);
200 bool visitBinLT(BinaryOperator
const * expr
);
202 bool visitBinGT(BinaryOperator
const * expr
);
204 bool visitBinLE(BinaryOperator
const * expr
);
206 bool visitBinGE(BinaryOperator
const * expr
);
208 bool visitBinEQ(BinaryOperator
const * expr
);
210 bool visitBinNE(BinaryOperator
const * expr
);
212 FunctionDecl
* m_insideFunctionDecl
= nullptr;
215 void SimplifyBool::run() {
216 if (compiler
.getLangOpts().CPlusPlus
) {
217 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
221 bool SimplifyBool::VisitUnaryOperator(UnaryOperator
const * expr
) {
222 if (expr
->getOpcode() != UO_LNot
) {
225 if (ignoreLocation(expr
)) {
228 auto e
= getSubExprOfLogicalNegation(expr
->getSubExpr());
230 // Ignore macros, otherwise
231 // OSL_ENSURE(!b, ...);
233 if (e
->getBeginLoc().isMacroID())
235 // double logical not of an int is an idiom to convert to bool
236 auto const sub
= ignoreAllImplicit(e
);
237 if (!sub
->getType()->isBooleanType())
240 DiagnosticsEngine::Warning
,
241 ("double logical negation expression of the form '!!A' (with A of type"
242 " %0) can %select{logically|literally}1 be simplified as 'A'"),
245 << sub
->getType()->isBooleanType()
246 << expr
->getSourceRange();
249 auto sub
= expr
->getSubExpr()->IgnoreParenImpCasts();
250 auto reversed
= false;
251 if (auto const rewritten
= dyn_cast
<CXXRewrittenBinaryOperator
>(sub
)) {
252 if (rewritten
->isReversed()) {
253 if (rewritten
->getOperator() == BO_EQ
) {
254 auto const sem
= rewritten
->getSemanticForm();
256 if (auto const op1
= dyn_cast
<BinaryOperator
>(sem
)) {
257 match
= op1
->getOpcode() == BO_EQ
;
258 } else if (auto const op2
= dyn_cast
<CXXOperatorCallExpr
>(sem
)) {
259 match
= op2
->getOperator() == OO_EqualEqual
;
270 if (auto binaryOp
= dyn_cast
<BinaryOperator
>(sub
)) {
271 // Ignore macros, otherwise
272 // OSL_ENSURE(!b, ...);
274 if (binaryOp
->getBeginLoc().isMacroID())
276 if (binaryOp
->isComparisonOp())
278 auto t
= binaryOp
->getLHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
279 if (t
->isTemplateTypeParmType() || t
->isDependentType() || t
->isRecordType())
281 // for floating point (with NaN) !(x<y) need not be equivalent to x>=y
282 if (t
->isFloatingType() ||
283 binaryOp
->getRHS()->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType()->isFloatingType())
286 DiagnosticsEngine::Warning
,
287 ("logical negation of comparison operator, can be simplified by inverting operator"),
289 << expr
->getSourceRange();
291 else if (binaryOp
->isLogicalOp())
293 // if we find a negation condition inside, it is definitely better
295 bool foundLNot
= false;
296 auto containsNegationOrComparison
= [&](Expr
const * expr
) {
297 expr
= ignoreParenImpCastAndComma(expr
);
298 if (auto unaryOp
= dyn_cast
<UnaryOperator
>(expr
))
299 if (unaryOp
->getOpcode() == UO_LNot
)
304 if (auto binaryOp
= dyn_cast
<BinaryOperator
>(expr
))
305 if (binaryOp
->isComparisonOp())
307 if (auto cxxOpCall
= dyn_cast
<CXXOperatorCallExpr
>(expr
))
308 if (cxxOpCall
->isComparisonOp())
310 return (Expr
const*)nullptr;
312 auto lhs
= containsNegationOrComparison(binaryOp
->getLHS());
313 auto rhs
= containsNegationOrComparison(binaryOp
->getRHS());
314 if (foundLNot
|| (lhs
&& rhs
))
316 DiagnosticsEngine::Warning
,
317 ("logical negation of logical op containing negation, can be simplified"),
318 binaryOp
->getBeginLoc())
319 << binaryOp
->getSourceRange();
322 if (auto binaryOp
= dyn_cast
<CXXOperatorCallExpr
>(sub
)) {
323 // Ignore macros, otherwise
324 // OSL_ENSURE(!b, ...);
326 if (binaryOp
->getBeginLoc().isMacroID())
328 auto op
= binaryOp
->getOperator();
329 // Negating things like > and >= would probably not be wise, there is no guarantee the negation holds for operator overloaded types.
330 // However, == and != are normally considered ok.
331 if (!(op
== OO_EqualEqual
|| op
== OO_ExclaimEqual
))
333 BinaryOperator::Opcode negatedOpcode
= BinaryOperator::negateComparisonOp(BinaryOperator::getOverloadedOpcode(op
));
334 auto lhs
= binaryOp
->getArg(reversed
? 1 : 0)->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
335 auto rhs
= binaryOp
->getArg(reversed
? 0 : 1)->IgnoreImpCasts()->getType()->getUnqualifiedDesugaredType();
336 auto const negOp
= findOperator(compiler
, negatedOpcode
, lhs
, rhs
);
339 // if we are inside a similar operator, ignore, eg. operator!= is often defined by calling !operator==
340 if (m_insideFunctionDecl
&& m_insideFunctionDecl
->getNumParams() >= 1) {
341 auto t
= stripConstRef(m_insideFunctionDecl
->getParamDecl(0)->getType().getTypePtr());
346 StringRef
fn(handler
.getMainFileName());
347 if (loplugin::isSamePathname(fn
, SRCDIR
"/testtools/source/bridgetest/bridgetest.cxx"))
350 DiagnosticsEngine::Warning
,
351 ("logical negation of comparison operator, can be simplified by inverting operator"),
353 << expr
->getSourceRange();
354 if (negOp
!= ASSUME_OPERATOR_EXISTS
)
356 DiagnosticsEngine::Note
, "the presumed corresponding negated operator for %0 and %1 is declared here",
357 negOp
->getLocation())
358 << binaryOp
->getArg(reversed
? 1 : 0)->IgnoreImpCasts()->getType()
359 << binaryOp
->getArg(reversed
? 0 : 1)->IgnoreImpCasts()->getType()
360 << negOp
->getSourceRange();
365 bool SimplifyBool::VisitBinaryOperator(BinaryOperator
const * expr
) {
366 switch (expr
->getOpcode()) {
368 return visitBinLT(expr
);
370 return visitBinGT(expr
);
372 return visitBinLE(expr
);
374 return visitBinGE(expr
);
376 return visitBinEQ(expr
);
378 return visitBinNE(expr
);
384 bool SimplifyBool::visitBinLT(BinaryOperator
const * expr
) {
385 if (ignoreLocation(expr
)) {
388 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
389 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
393 auto v1
= getValue(expr
->getLHS());
394 auto v2
= getValue(expr
->getRHS());
402 DiagnosticsEngine::Warning
,
403 ("less-than expression of the form 'A < false' (with A of type"
404 " %0) can logically be simplified as 'false'"),
406 << expr
->getLHS()->IgnoreImpCasts()->getType()
407 << expr
->getSourceRange();
411 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
414 DiagnosticsEngine::Warning
,
415 ("less-than expression of the form 'A < true' (with A"
416 " of type %0) can %select{logically|literally}1 be"
417 " simplified as '!A'"),
419 << expr
->getLHS()->IgnoreImpCasts()->getType()
420 << (expr
->getLHS()->IgnoreImpCasts()->getType()
422 << expr
->getSourceRange();
425 DiagnosticsEngine::Warning
,
426 ("less-than expression of the form '!A < true' (with A"
427 " of type %0) can %select{logically|literally}1 be"
428 " simplified as 'A'"),
430 << e
->IgnoreImpCasts()->getType()
431 << e
->IgnoreImpCasts()->getType()->isBooleanType()
432 << expr
->getSourceRange();
442 DiagnosticsEngine::Warning
,
443 ("less-than expression of the form 'false < A' (with A of type"
444 " %0) can %select{logically|literally}1 be simplified as 'A'"),
446 << expr
->getRHS()->IgnoreImpCasts()->getType()
447 << expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
448 << expr
->getSourceRange();
452 DiagnosticsEngine::Warning
,
453 ("less-than expression of the form 'false < false' can"
454 " literally be simplified as 'false'"),
456 << expr
->getSourceRange();
460 DiagnosticsEngine::Warning
,
461 ("less-than expression of the form 'false < true' can"
462 " literally be simplified as 'true'"),
464 << expr
->getSourceRange();
472 DiagnosticsEngine::Warning
,
473 ("less-than expression of the form 'true < A' (with A of type"
474 " %0) can logically be simplified as 'false'"),
476 << expr
->getRHS()->IgnoreImpCasts()->getType()
477 << expr
->getSourceRange();
481 DiagnosticsEngine::Warning
,
482 ("less-than expression of the form 'true < false' can"
483 " literally be simplified as 'false'"),
485 << expr
->getSourceRange();
489 DiagnosticsEngine::Warning
,
490 ("less-than expression of the form 'true < true' can"
491 " literally be simplified as 'false'"),
493 << expr
->getSourceRange();
501 bool SimplifyBool::visitBinGT(BinaryOperator
const * expr
) {
502 if (ignoreLocation(expr
)) {
505 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
506 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
510 auto v1
= getValue(expr
->getLHS());
511 auto v2
= getValue(expr
->getRHS());
519 DiagnosticsEngine::Warning
,
520 ("greater-than expression of the form 'A > false' (with A of"
521 " type %0) can %select{logically|literally}1 be simplified as"
524 << expr
->getLHS()->IgnoreImpCasts()->getType()
525 << expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
526 << expr
->getSourceRange();
530 DiagnosticsEngine::Warning
,
531 ("greater-than expression of the form 'A > true' (with A of"
532 " type %0) can logically be simplified as 'false'"),
534 << expr
->getLHS()->IgnoreImpCasts()->getType()
535 << expr
->getSourceRange();
543 DiagnosticsEngine::Warning
,
544 ("greater-than expression of the form 'false > A' (with A of"
545 " type %0) can logically be simplified as 'false'"),
547 << expr
->getRHS()->IgnoreImpCasts()->getType()
548 << expr
->getSourceRange();
552 DiagnosticsEngine::Warning
,
553 ("greater-than expression of the form 'false > false' can"
554 " literally be simplified as 'false'"),
556 << expr
->getSourceRange();
560 DiagnosticsEngine::Warning
,
561 ("greater-than expression of the form 'false > true' can"
562 " literally be simplified as 'false'"),
564 << expr
->getSourceRange();
572 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
575 DiagnosticsEngine::Warning
,
576 ("greater-than expression of the form 'true > A' (with"
577 " A of type %0) can %select{logically|literally}1 be"
578 " simplified as '!A'"),
580 << expr
->getRHS()->IgnoreImpCasts()->getType()
581 << (expr
->getRHS()->IgnoreImpCasts()->getType()
583 << expr
->getSourceRange();
586 DiagnosticsEngine::Warning
,
587 ("greater-than expression of the form 'true > !A' (with"
588 " A of type %0) can %select{logically|literally}1 be"
589 " simplified as 'A'"),
591 << e
->IgnoreImpCasts()->getType()
592 << e
->IgnoreImpCasts()->getType()->isBooleanType()
593 << expr
->getSourceRange();
599 DiagnosticsEngine::Warning
,
600 ("greater-than expression of the form 'true > false' can"
601 " literally be simplified as 'true'"),
603 << expr
->getSourceRange();
607 DiagnosticsEngine::Warning
,
608 ("greater-than expression of the form 'true > true' can"
609 " literally be simplified as 'false'"),
611 << expr
->getSourceRange();
619 bool SimplifyBool::visitBinLE(BinaryOperator
const * expr
) {
620 if (ignoreLocation(expr
)) {
623 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
624 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
628 auto v1
= getValue(expr
->getLHS());
629 auto v2
= getValue(expr
->getRHS());
637 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
640 DiagnosticsEngine::Warning
,
641 ("less-than-or-equal-to expression of the form 'A <="
642 " false' (with A of type %0) can"
643 " %select{logically|literally}1 be simplified as"
646 << expr
->getLHS()->IgnoreImpCasts()->getType()
647 << (expr
->getLHS()->IgnoreImpCasts()->getType()
649 << expr
->getSourceRange();
652 DiagnosticsEngine::Warning
,
653 ("less-than-or-equal-to expression of the form '!A <="
654 " false' (with A of type %0) can"
655 " %select{logically|literally}1 be simplified as 'A'"),
657 << e
->IgnoreImpCasts()->getType()
658 << e
->IgnoreImpCasts()->getType()->isBooleanType()
659 << expr
->getSourceRange();
665 DiagnosticsEngine::Warning
,
666 ("less-than-or-equal-to expression of the form 'A <= true'"
667 " (with A of type %0) can logically be simplified as 'true'"),
669 << expr
->getLHS()->IgnoreImpCasts()->getType()
670 << expr
->getSourceRange();
678 DiagnosticsEngine::Warning
,
679 ("less-than-or-equal-to expression of the form 'false <= A'"
680 " (with A of type %0) can logically be simplified as 'true'"),
682 << expr
->getRHS()->IgnoreImpCasts()->getType()
683 << expr
->getSourceRange();
687 DiagnosticsEngine::Warning
,
688 ("less-than-or-equal-to expression of the form 'false <= false'"
689 " can literally be simplified as 'true'"),
691 << expr
->getSourceRange();
695 DiagnosticsEngine::Warning
,
696 ("less-than-or-equal-to expression of the form 'false <= true'"
697 " can literally be simplified as 'true'"),
699 << expr
->getSourceRange();
707 DiagnosticsEngine::Warning
,
708 ("less-than-or-equal-to expression of the form 'true <= A'"
709 " (with A of type %0) can %select{logically|literally}1 be"
710 " simplified as 'A'"),
712 << expr
->getRHS()->IgnoreImpCasts()->getType()
713 << expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
714 << expr
->getSourceRange();
718 DiagnosticsEngine::Warning
,
719 ("less-than-or-equal-to expression of the form 'true <= false'"
720 " can literally be simplified as 'false'"),
722 << expr
->getSourceRange();
726 DiagnosticsEngine::Warning
,
727 ("less-than-or-equal-to expression of the form 'true <= true'"
728 " can literally be simplified as 'true'"),
730 << expr
->getSourceRange();
738 bool SimplifyBool::visitBinGE(BinaryOperator
const * expr
) {
739 if (ignoreLocation(expr
)) {
742 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
743 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
747 auto v1
= getValue(expr
->getLHS());
748 auto v2
= getValue(expr
->getRHS());
756 DiagnosticsEngine::Warning
,
757 ("greater-than-or-equal-to expression of the form 'A >= false'"
758 " (with A of type %0) can logically be simplified as 'true'"),
760 << expr
->getLHS()->IgnoreImpCasts()->getType()
761 << expr
->getSourceRange();
765 DiagnosticsEngine::Warning
,
766 ("greater-than-or-equal-to expression of the form 'A >= true'"
767 " (with A of type %0) can %select{logically|literally}1 be"
768 " simplified as 'A'"),
770 << expr
->getLHS()->IgnoreImpCasts()->getType()
771 << expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
772 << expr
->getSourceRange();
780 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
783 DiagnosticsEngine::Warning
,
784 ("greater-than-or-equal-to expression of the form"
785 " 'false >= A' (with A of type %0) can"
786 " %select{logically|literally}1 be simplified as"
789 << expr
->getRHS()->IgnoreImpCasts()->getType()
790 << (expr
->getRHS()->IgnoreImpCasts()->getType()
792 << expr
->getSourceRange();
795 DiagnosticsEngine::Warning
,
796 ("greater-than-or-equal-to expression of the form"
797 " 'false >= !A' (with A of type %0) can"
798 " %select{logically|literally}1 be simplified as 'A'"),
800 << e
->IgnoreImpCasts()->getType()
801 << e
->IgnoreImpCasts()->getType()->isBooleanType()
802 << expr
->getSourceRange();
808 DiagnosticsEngine::Warning
,
809 ("greater-than-or-equal-to expression of the form 'false >="
810 " false' can literally be simplified as 'true'"),
812 << expr
->getSourceRange();
816 DiagnosticsEngine::Warning
,
817 ("greater-than-or-equal-to expression of the form 'false >="
818 " true' can literally be simplified as 'false'"),
820 << expr
->getSourceRange();
828 DiagnosticsEngine::Warning
,
829 ("greater-than-or-equal-to expression of the form 'true >= A'"
830 " (with A of type %0) can logically be simplified as 'true'"),
832 << expr
->getRHS()->IgnoreImpCasts()->getType()
833 << expr
->getSourceRange();
837 DiagnosticsEngine::Warning
,
838 ("greater-than-or-equal-to expression of the form 'true >="
839 " false' can literally be simplified as 'true'"),
841 << expr
->getSourceRange();
845 DiagnosticsEngine::Warning
,
846 ("greater-than-or-equal-to expression of the form 'true >="
847 " true' can literally be simplified as 'true'"),
849 << expr
->getSourceRange();
857 bool SimplifyBool::visitBinEQ(BinaryOperator
const * expr
) {
858 if (ignoreLocation(expr
)) {
861 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
862 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
866 auto v1
= getValue(expr
->getLHS());
867 auto v2
= getValue(expr
->getRHS());
875 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
878 DiagnosticsEngine::Warning
,
879 ("equal-to expression of the form 'A == false' (with A"
880 " of type %0) can %select{logically|literally}1 be"
881 " simplified as '!A'"),
883 << expr
->getLHS()->IgnoreImpCasts()->getType()
884 << (expr
->getLHS()->IgnoreImpCasts()->getType()
886 << expr
->getSourceRange();
889 DiagnosticsEngine::Warning
,
890 ("equal-to expression of the form '!A == false' (with A"
891 " of type %0) can %select{logically|literally}1 be"
892 " simplified as 'A'"),
894 << e
->IgnoreImpCasts()->getType()
895 << e
->IgnoreImpCasts()->getType()->isBooleanType()
896 << expr
->getSourceRange();
902 DiagnosticsEngine::Warning
,
903 ("equal-to expression of the form 'A == true' (with A of type"
904 " %0) can %select{logically|literally}1 be simplified as 'A'"),
906 << expr
->getLHS()->IgnoreImpCasts()->getType()
907 << expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
908 << expr
->getSourceRange();
916 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
919 DiagnosticsEngine::Warning
,
920 ("equal-to expression of the form 'false == A' (with A"
921 " of type %0) can %select{logically|literally}1 be"
922 " simplified as '!A'"),
924 << expr
->getRHS()->IgnoreImpCasts()->getType()
925 << (expr
->getRHS()->IgnoreImpCasts()->getType()
927 << expr
->getSourceRange();
930 DiagnosticsEngine::Warning
,
931 ("equal-to expression of the form 'false == !A' (with A"
932 " of type %0) can %select{logically|literally}1 be"
933 " simplified as 'A'"),
935 << e
->IgnoreImpCasts()->getType()
936 << e
->IgnoreImpCasts()->getType()->isBooleanType()
937 << expr
->getSourceRange();
943 DiagnosticsEngine::Warning
,
944 ("equal-to expression of the form 'false == false' can"
945 " literally be simplified as 'true'"),
947 << expr
->getSourceRange();
951 DiagnosticsEngine::Warning
,
952 ("equal-to expression of the form 'false == true' can"
953 " literally be simplified as 'false'"),
955 << expr
->getSourceRange();
963 DiagnosticsEngine::Warning
,
964 ("equal-to expression of the form 'true == A' (with A of type"
965 " %0) can %select{logically|literally}1 be simplified as 'A'"),
967 << expr
->getRHS()->IgnoreImpCasts()->getType()
968 << expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
969 << expr
->getSourceRange();
973 DiagnosticsEngine::Warning
,
974 ("equal-to expression of the form 'true == false' can"
975 " literally be simplified as 'false'"),
977 << expr
->getSourceRange();
981 DiagnosticsEngine::Warning
,
982 ("equal-to expression of the form 'true == true' can"
983 " literally be simplified as 'true'"),
985 << expr
->getSourceRange();
993 bool SimplifyBool::visitBinNE(BinaryOperator
const * expr
) {
994 if (ignoreLocation(expr
)) {
997 if (!(expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
998 && expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()))
1002 auto v1
= getValue(expr
->getLHS());
1003 auto v2
= getValue(expr
->getRHS());
1005 case Value::Unknown
:
1007 case Value::Unknown
:
1011 DiagnosticsEngine::Warning
,
1012 ("not-equal-to expression of the form 'A != false' (with A of"
1013 " type %0) can %select{logically|literally}1 be simplified as"
1015 expr
->getBeginLoc())
1016 << expr
->getLHS()->IgnoreImpCasts()->getType()
1017 << expr
->getLHS()->IgnoreImpCasts()->getType()->isBooleanType()
1018 << expr
->getSourceRange();
1022 auto e
= getSubExprOfLogicalNegation(expr
->getLHS());
1025 DiagnosticsEngine::Warning
,
1026 ("not-equal-to expression of the form 'A != true' (with"
1027 " A of type %0) can %select{logically|literally}1 be"
1028 " simplified as '!A'"),
1029 expr
->getBeginLoc())
1030 << expr
->getLHS()->IgnoreImpCasts()->getType()
1031 << (expr
->getLHS()->IgnoreImpCasts()->getType()
1033 << expr
->getSourceRange();
1036 DiagnosticsEngine::Warning
,
1037 ("not-equal-to expression of the form '!A != true'"
1038 " (with A of type %0) can"
1039 " %select{logically|literally}1 be simplified as 'A'"),
1040 expr
->getBeginLoc())
1041 << e
->IgnoreImpCasts()->getType()
1042 << e
->IgnoreImpCasts()->getType()->isBooleanType()
1043 << expr
->getSourceRange();
1051 case Value::Unknown
:
1053 DiagnosticsEngine::Warning
,
1054 ("not-equal-to expression of the form 'false != A' (with A of"
1055 " type %0) can %select{logically|literally}1 be simplified as"
1057 expr
->getBeginLoc())
1058 << expr
->getRHS()->IgnoreImpCasts()->getType()
1059 << expr
->getRHS()->IgnoreImpCasts()->getType()->isBooleanType()
1060 << expr
->getSourceRange();
1064 DiagnosticsEngine::Warning
,
1065 ("not-equal-to expression of the form 'false != false' can"
1066 " literally be simplified as 'false'"),
1067 expr
->getBeginLoc())
1068 << expr
->getSourceRange();
1072 DiagnosticsEngine::Warning
,
1073 ("not-equal-to expression of the form 'false != true' can"
1074 " literally be simplified as 'true'"),
1075 expr
->getBeginLoc())
1076 << expr
->getSourceRange();
1082 case Value::Unknown
:
1084 auto e
= getSubExprOfLogicalNegation(expr
->getRHS());
1087 DiagnosticsEngine::Warning
,
1088 ("not-equal-to expression of the form 'true != A' (with"
1089 " A of type %0) can %select{logically|literally}1 be"
1090 " simplified as '!A'"),
1091 expr
->getBeginLoc())
1092 << expr
->getRHS()->IgnoreImpCasts()->getType()
1093 << (expr
->getRHS()->IgnoreImpCasts()->getType()
1095 << expr
->getSourceRange();
1098 DiagnosticsEngine::Warning
,
1099 ("not-equal-to expression of the form 'true != !A'"
1100 " (with A of type %0) can"
1101 " %select{logically|literally}1 be simplified as 'A'"),
1102 expr
->getBeginLoc())
1103 << e
->IgnoreImpCasts()->getType()
1104 << e
->IgnoreImpCasts()->getType()->isBooleanType()
1105 << expr
->getSourceRange();
1111 DiagnosticsEngine::Warning
,
1112 ("not-equal-to expression of the form 'true != false' can"
1113 " literally be simplified as 'true'"),
1114 expr
->getBeginLoc())
1115 << expr
->getSourceRange();
1119 DiagnosticsEngine::Warning
,
1120 ("not-equal-to expression of the form 'true != true' can"
1121 " literally be simplified as 'false'"),
1122 expr
->getBeginLoc())
1123 << expr
->getSourceRange();
1131 bool SimplifyBool::VisitConditionalOperator(ConditionalOperator
const * expr
) {
1132 if (ignoreLocation(expr
)) {
1135 auto v1
= getValue(expr
->getTrueExpr());
1136 auto v2
= getValue(expr
->getFalseExpr());
1138 case Value::Unknown
:
1140 case Value::Unknown
:
1144 DiagnosticsEngine::Warning
,
1145 ("conditional expression of the form 'A ? B : false' (with A of"
1146 " type %0 and B of type %1) can %select{logically|literally}2"
1147 " be simplified as 'A && B'"),
1148 expr
->getBeginLoc())
1149 << expr
->getCond()->IgnoreImpCasts()->getType()
1150 << expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1151 << ((expr
->getCond()->IgnoreImpCasts()->getType()
1153 && (expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1155 << expr
->getSourceRange();
1159 auto e
= getSubExprOfLogicalNegation(expr
->getCond());
1162 DiagnosticsEngine::Warning
,
1163 ("conditional expression of the form 'A ? B : true'"
1164 " (with A of type %0 and B of type %1) can"
1165 " %select{logically|literally}2 be simplified as '!A"
1167 expr
->getBeginLoc())
1168 << expr
->getCond()->IgnoreImpCasts()->getType()
1169 << expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1170 << ((expr
->getCond()->IgnoreImpCasts()->getType()
1172 && (expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1174 << expr
->getSourceRange();
1177 DiagnosticsEngine::Warning
,
1178 ("conditional expression of the form '!A ? B : true'"
1179 " (with A of type %0 and B of type %1) can"
1180 " %select{logically|literally}2 be simplified as 'A ||"
1182 expr
->getBeginLoc())
1183 << e
->IgnoreImpCasts()->getType()
1184 << expr
->getTrueExpr()->IgnoreImpCasts()->getType()
1185 << (e
->IgnoreImpCasts()->getType()->isBooleanType()
1186 && (expr
->getTrueExpr()->IgnoreImpCasts()
1187 ->getType()->isBooleanType()))
1188 << expr
->getSourceRange();
1196 case Value::Unknown
:
1198 auto e
= getSubExprOfLogicalNegation(expr
->getCond());
1201 DiagnosticsEngine::Warning
,
1202 ("conditional expression of the form 'A ? false : B'"
1203 " (with A of type %0 and B of type %1) can"
1204 " %select{logically|literally}2 be simplified as '!A"
1206 expr
->getBeginLoc())
1207 << expr
->getCond()->IgnoreImpCasts()->getType()
1208 << expr
->getFalseExpr()->IgnoreImpCasts()->getType()
1209 << ((expr
->getCond()->IgnoreImpCasts()->getType()
1211 && (expr
->getFalseExpr()->IgnoreImpCasts()
1212 ->getType()->isBooleanType()))
1213 << expr
->getSourceRange();
1216 DiagnosticsEngine::Warning
,
1217 ("conditional expression of the form '!A ? false : B'"
1218 " (with A of type %0 and B of type %1) can"
1219 " %select{logically|literally}2 be simplified as 'A &&"
1221 expr
->getBeginLoc())
1222 << e
->IgnoreImpCasts()->getType()
1223 << expr
->getFalseExpr()->IgnoreImpCasts()->getType()
1224 << (e
->IgnoreImpCasts()->getType()->isBooleanType()
1225 && (expr
->getFalseExpr()->IgnoreImpCasts()
1226 ->getType()->isBooleanType()))
1227 << expr
->getSourceRange();
1233 DiagnosticsEngine::Warning
,
1234 ("conditional expression of the form 'A ? false : false' (with"
1235 " A of type %0) can logically be simplified as 'false'"),
1236 expr
->getBeginLoc())
1237 << expr
->getCond()->IgnoreImpCasts()->getType()
1238 << expr
->getSourceRange();
1242 auto e
= getSubExprOfLogicalNegation(expr
->getCond());
1245 DiagnosticsEngine::Warning
,
1246 ("conditional expression of the form 'A ? false : true'"
1247 " (with A of type %0) can"
1248 " %select{logically|literally}1 be simplified as"
1250 expr
->getBeginLoc())
1251 << expr
->getCond()->IgnoreImpCasts()->getType()
1252 << (expr
->getCond()->IgnoreImpCasts()->getType()
1254 << expr
->getSourceRange();
1257 DiagnosticsEngine::Warning
,
1258 ("conditional expression of the form '!A ? false :"
1259 " true' (with A of type %0) can"
1260 " %select{logically|literally}1 be simplified as 'A'"),
1261 expr
->getBeginLoc())
1262 << e
->IgnoreImpCasts()->getType()
1263 << e
->IgnoreImpCasts()->getType()->isBooleanType()
1264 << expr
->getSourceRange();
1272 case Value::Unknown
:
1274 DiagnosticsEngine::Warning
,
1275 ("conditional expression of the form 'A ? true : B' (with A of"
1276 " type %0 and B of type %1) can %select{logically|literally}2"
1277 " be simplified as 'A || B'"),
1278 expr
->getBeginLoc())
1279 << expr
->getCond()->IgnoreImpCasts()->getType()
1280 << expr
->getFalseExpr()->IgnoreImpCasts()->getType()
1281 << ((expr
->getCond()->IgnoreImpCasts()->getType()
1283 && (expr
->getFalseExpr()->IgnoreImpCasts()->getType()
1285 << expr
->getSourceRange();
1289 DiagnosticsEngine::Warning
,
1290 ("conditional expression of the form 'A ? true : false' (with A"
1291 " of type %0) can %select{logically|literally}1 be simplified"
1293 expr
->getBeginLoc())
1294 << expr
->getCond()->IgnoreImpCasts()->getType()
1295 << expr
->getCond()->IgnoreImpCasts()->getType()->isBooleanType()
1296 << expr
->getSourceRange();
1300 DiagnosticsEngine::Warning
,
1301 ("conditional expression of the form 'A ? true : true' (with A"
1302 " of type %0) can logically be simplified as 'true'"),
1303 expr
->getBeginLoc())
1304 << expr
->getCond()->IgnoreImpCasts()->getType()
1305 << expr
->getSourceRange();
1313 bool SimplifyBool::TraverseFunctionDecl(FunctionDecl
* functionDecl
) {
1314 auto copy
= m_insideFunctionDecl
;
1315 m_insideFunctionDecl
= functionDecl
;
1316 bool ret
= RecursiveASTVisitor::TraverseFunctionDecl(functionDecl
);
1317 m_insideFunctionDecl
= copy
;
1321 bool SimplifyBool::TraverseCXXMethodDecl(CXXMethodDecl
* functionDecl
) {
1322 auto copy
= m_insideFunctionDecl
;
1323 m_insideFunctionDecl
= functionDecl
;
1324 bool ret
= RecursiveASTVisitor::TraverseCXXMethodDecl(functionDecl
);
1325 m_insideFunctionDecl
= copy
;
1329 loplugin::Plugin::Registration
<SimplifyBool
> X("simplifybool");
1333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */