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/.
18 #include "clang/Basic/Builtins.h"
26 Expr
const * ignoreParenAndTemporaryMaterialization(Expr
const * expr
) {
28 expr
= expr
->IgnoreParens();
29 auto e
= dyn_cast
<MaterializeTemporaryExpr
>(expr
);
33 expr
= e
->getSubExpr();
37 Expr
const * ignoreParenImpCastAndComma(Expr
const * expr
) {
39 expr
= expr
->IgnoreParenImpCasts();
40 BinaryOperator
const * op
= dyn_cast
<BinaryOperator
>(expr
);
41 if (op
== nullptr || op
->getOpcode() != BO_Comma
) {
48 SubstTemplateTypeParmType
const * getAsSubstTemplateTypeParmType(QualType type
)
50 //TODO: unwrap all kinds of (non-SubstTemplateTypeParmType) sugar, not only
53 TypedefType
const * t
= type
->getAs
<TypedefType
>();
55 return dyn_cast
<SubstTemplateTypeParmType
>(type
);
61 QualType
reconstructTemplateArgumentType(
62 TemplateDecl
const * decl
, TemplateSpecializationType
const * specializationType
,
63 SubstTemplateTypeParmType
const * parmType
)
65 TemplateParameterList
const * ps
= decl
->getTemplateParameters();
66 auto i
= std::find(ps
->begin(), ps
->end(), compat::getReplacedParameter(parmType
));
70 auto const args
= specializationType
->template_arguments();
71 if (ps
->size() != args
.size()) { //TODO
74 TemplateArgument
const & arg
= args
[i
- ps
->begin()];
75 if (arg
.getKind() != TemplateArgument::Type
) {
78 return arg
.getAsType();
81 bool areSameTypedef(QualType type1
, QualType type2
) {
82 // type1.getTypePtr() == typ2.getTypePtr() fails for e.g. ::sal_Bool vs.
84 auto t1
= type1
->getAs
<TypedefType
>();
85 auto t2
= type2
->getAs
<TypedefType
>();
86 return t1
!= nullptr && t2
!= nullptr && t1
->getDecl() == t2
->getDecl();
89 bool isBool(Expr
const * expr
, bool allowTypedefs
= true) {
90 auto t
= expr
->getType();
92 ? bool(loplugin::TypeCheck(t
).AnyBoolean()) : t
->isBooleanType();
95 bool isMatchingBool(Expr
const * expr
, Expr
const * comparisonExpr
) {
96 return isBool(expr
, false)
97 || areSameTypedef(expr
->getType(), comparisonExpr
->getType());
100 bool isSalBool(QualType type
) {
101 auto t
= type
->getAs
<TypedefType
>();
102 return t
!= nullptr && t
->getDecl()->getName() == "sal_Bool";
105 bool isBoolExpr(Expr
const * expr
) {
109 expr
= ignoreParenImpCastAndComma(expr
);
110 ConditionalOperator
const * co
= dyn_cast
<ConditionalOperator
>(expr
);
112 ImplicitCastExpr
const * ic1
= dyn_cast
<ImplicitCastExpr
>(
113 co
->getTrueExpr()->IgnoreParens());
114 ImplicitCastExpr
const * ic2
= dyn_cast
<ImplicitCastExpr
>(
115 co
->getFalseExpr()->IgnoreParens());
116 if (ic1
!= nullptr && ic2
!= nullptr
117 && ic1
->getType()->isSpecificBuiltinType(BuiltinType::Int
)
118 && isBoolExpr(ic1
->getSubExpr()->IgnoreParens())
119 && ic2
->getType()->isSpecificBuiltinType(BuiltinType::Int
)
120 && isBoolExpr(ic2
->getSubExpr()->IgnoreParens()))
125 std::stack
<Expr
const *> stack
;
126 Expr
const * e
= expr
;
128 e
= ignoreParenImpCastAndComma(e
);
129 MemberExpr
const * me
= dyn_cast
<MemberExpr
>(e
);
137 e
= ignoreParenImpCastAndComma(e
);
138 CXXOperatorCallExpr
const * op
= dyn_cast
<CXXOperatorCallExpr
>(e
);
139 if (op
== nullptr || op
->getOperator() != OO_Subscript
) {
145 if (!stack
.empty()) {
146 TemplateSpecializationType
const * t
147 = e
->getType()->getAs
<TemplateSpecializationType
>();
153 MemberExpr
const * me
= dyn_cast
<MemberExpr
>(stack
.top());
155 TemplateDecl
const * td
156 = t
->getTemplateName().getAsTemplateDecl();
160 SubstTemplateTypeParmType
const * t2
161 = getAsSubstTemplateTypeParmType(
162 me
->getMemberDecl()->getType());
166 ty
= reconstructTemplateArgumentType(td
, t
, t2
);
168 auto const canon
= cast
<TemplateDecl
>(td
->getCanonicalDecl());
170 ty
= reconstructTemplateArgumentType(canon
, t
, t2
);
177 CXXOperatorCallExpr
const * op
178 = dyn_cast
<CXXOperatorCallExpr
>(stack
.top());
179 assert(op
!= nullptr);
181 TemplateDecl
const * d
182 = t
->getTemplateName().getAsTemplateDecl();
186 auto const dc
= loplugin::DeclCheck(d
->getTemplatedDecl());
187 auto const args
= t
->template_arguments();
188 if (dc
.ClassOrStruct("array").StdNamespace() && args
.size() >= 2
189 && args
[0].getKind() == TemplateArgument::Type
)
191 ty
= args
[0].getAsType();
192 } else if (dc
.Class("Sequence").Namespace("uno").Namespace("star").Namespace("sun")
193 .Namespace("com").GlobalNamespace()
195 && args
[0].getKind() == TemplateArgument::Type
)
197 ty
= args
[0].getAsType();
204 if (loplugin::TypeCheck(ty
).AnyBoolean()) {
209 t
= ty
->getAs
<TemplateSpecializationType
>();
215 // It appears that, given a function declaration, there is no way to determine
216 // the language linkage of the function's type, only of the function's name
217 // (via FunctionDecl::isExternC); however, in a case like
219 // extern "C" { static void f(); }
221 // the function's name does not have C language linkage while the function's
222 // type does (as clarified in C++11 [decl.link]); cf. <http://clang-developers.
223 // 42468.n3.nabble.com/Language-linkage-of-function-type-tt4037248.html>
224 // "Language linkage of function type":
225 bool hasCLanguageLinkageType(FunctionDecl
const * decl
) {
226 assert(decl
!= nullptr);
227 if (decl
->isExternC()) {
230 if (decl
->isInExternCContext()) {
236 class ImplicitBoolConversion
:
237 public loplugin::FilteringPlugin
<ImplicitBoolConversion
>
240 explicit ImplicitBoolConversion(loplugin::InstantiationData
const & data
):
241 FilteringPlugin(data
) {}
243 virtual void run() override
244 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
246 bool TraverseCallExpr(CallExpr
* expr
);
248 bool TraverseCXXMemberCallExpr(CXXMemberCallExpr
* expr
);
250 bool TraverseCXXConstructExpr(CXXConstructExpr
* expr
);
252 bool TraverseCXXTemporaryObjectExpr(CXXTemporaryObjectExpr
* expr
);
254 bool TraverseCStyleCastExpr(CStyleCastExpr
* expr
);
256 bool TraverseCXXStaticCastExpr(CXXStaticCastExpr
* expr
);
258 bool TraverseCXXFunctionalCastExpr(CXXFunctionalCastExpr
* expr
);
260 bool TraverseConditionalOperator(ConditionalOperator
* expr
);
262 bool TraverseBinaryOperator(BinaryOperator
* expr
);
264 bool TraverseCompoundAssignOperator(CompoundAssignOperator
* expr
);
266 bool TraverseInitListExpr(InitListExpr
* expr
);
268 bool TraverseReturnStmt(ReturnStmt
* stmt
);
270 bool TraverseFunctionDecl(FunctionDecl
* decl
);
272 bool VisitImplicitCastExpr(ImplicitCastExpr
const * expr
);
274 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr
const * expr
);
277 bool isExternCFunctionCall(
278 CallExpr
const * expr
, FunctionProtoType
const ** functionType
);
280 bool isExternCFunctionCallReturningInt(Expr
const * expr
);
282 void checkCXXConstructExpr(CXXConstructExpr
const * expr
);
284 void reportWarning(ImplicitCastExpr
const * expr
);
286 std::stack
<std::vector
<ImplicitCastExpr
const *>> nested
;
287 std::stack
<CallExpr
const *> calls
;
288 bool bExternCIntFunctionDefinition
= false;
291 bool ImplicitBoolConversion::TraverseCallExpr(CallExpr
* expr
) {
292 nested
.push(std::vector
<ImplicitCastExpr
const *>());
294 bool bRet
= RecursiveASTVisitor::TraverseCallExpr(expr
);
295 FunctionProtoType
const * t
;
296 bool bExt
= isExternCFunctionCall(expr
, &t
);
297 assert(!nested
.empty());
298 for (auto i
: nested
.top()) {
299 auto j
= std::find_if(
300 expr
->arg_begin(), expr
->arg_end(),
302 return i
== ignoreParenAndTemporaryMaterialization(e
);
304 if (j
== expr
->arg_end()) {
307 std::ptrdiff_t n
= j
- expr
->arg_begin();
310 && static_cast<std::size_t>(n
) >= t
->getNumParams())
312 assert(t
->isVariadic());
313 // ignore bool to int promotions of variadic arguments
317 static_cast<std::size_t>(n
) < t
->getNumParams());
318 if (!(t
->getParamType(n
)->isSpecificBuiltinType(
320 || t
->getParamType(n
)->isSpecificBuiltinType(
322 || t
->getParamType(n
)->isSpecificBuiltinType(
333 // template<typename T> void f(T);
334 // f<sal_Bool>(true);
336 DeclRefExpr
const * dr
= dyn_cast
<DeclRefExpr
>(
337 expr
->getCallee()->IgnoreParenImpCasts());
338 if (dr
!= nullptr && dr
->hasExplicitTemplateArgs()) {
339 FunctionDecl
const * fd
340 = dyn_cast
<FunctionDecl
>(dr
->getDecl());
342 && static_cast<std::size_t>(n
) < fd
->getNumParams())
344 SubstTemplateTypeParmType
const * t2
345 = getAsSubstTemplateTypeParmType(
346 fd
->getParamDecl(n
)->getType()
347 .getNonReferenceType());
349 //TODO: fix this superficial nonsense check:
350 if (dr
->getNumTemplateArgs() == 1) {
351 auto const ta
= dr
->getTemplateArgs();
352 if ((ta
[0].getArgument().getKind()
353 == TemplateArgument::Type
)
354 && (loplugin::TypeCheck(
355 ta
[0].getTypeSourceInfo()
374 bool ImplicitBoolConversion::TraverseCXXMemberCallExpr(CXXMemberCallExpr
* expr
)
376 nested
.push(std::vector
<ImplicitCastExpr
const *>());
377 bool bRet
= RecursiveASTVisitor::TraverseCXXMemberCallExpr(expr
);
378 assert(!nested
.empty());
379 for (auto i
: nested
.top()) {
380 auto j
= std::find_if(
381 expr
->arg_begin(), expr
->arg_end(),
383 return i
== ignoreParenAndTemporaryMaterialization(e
);
385 if (j
!= expr
->arg_end()) {
388 // template<typename T> struct S { void f(T); };
392 std::ptrdiff_t n
= j
- expr
->arg_begin();
394 CXXMethodDecl
const * d
= expr
->getMethodDecl();
395 if (static_cast<std::size_t>(n
) >= d
->getNumParams()) {
396 // Ignore bool to int promotions of variadic arguments:
397 assert(d
->isVariadic());
401 = ignoreParenImpCastAndComma(expr
->getImplicitObjectArgument())
403 if (dyn_cast
<MemberExpr
>(expr
->getCallee())->isArrow()) {
404 ty
= ty
->getAs
<clang::PointerType
>()->getPointeeType();
406 TemplateSpecializationType
const * ct
407 = ty
->getAs
<TemplateSpecializationType
>();
409 SubstTemplateTypeParmType
const * pt
410 = getAsSubstTemplateTypeParmType(
411 d
->getParamDecl(n
)->getType().getNonReferenceType());
413 TemplateDecl
const * td
414 = ct
->getTemplateName().getAsTemplateDecl();
416 //TODO: fix this superficial nonsense check:
417 auto const args
= ct
->template_arguments();
419 && args
[0].getKind() == TemplateArgument::Type
420 && (loplugin::TypeCheck(args
[0].getAsType())
435 bool ImplicitBoolConversion::TraverseCXXConstructExpr(CXXConstructExpr
* expr
) {
436 nested
.push(std::vector
<ImplicitCastExpr
const *>());
437 bool bRet
= RecursiveASTVisitor::TraverseCXXConstructExpr(expr
);
438 checkCXXConstructExpr(expr
);
443 bool ImplicitBoolConversion::TraverseCXXTemporaryObjectExpr(
444 CXXTemporaryObjectExpr
* expr
)
446 nested
.push(std::vector
<ImplicitCastExpr
const *>());
447 bool bRet
= RecursiveASTVisitor::TraverseCXXTemporaryObjectExpr(expr
);
448 checkCXXConstructExpr(expr
);
453 bool ImplicitBoolConversion::TraverseCStyleCastExpr(CStyleCastExpr
* expr
) {
454 nested
.push(std::vector
<ImplicitCastExpr
const *>());
455 bool bRet
= RecursiveASTVisitor::TraverseCStyleCastExpr(expr
);
456 assert(!nested
.empty());
457 for (auto i
: nested
.top()) {
458 if (i
!= expr
->getSubExpr()->IgnoreParens()) {
466 bool ImplicitBoolConversion::TraverseCXXStaticCastExpr(CXXStaticCastExpr
* expr
)
468 nested
.push(std::vector
<ImplicitCastExpr
const *>());
469 bool bRet
= RecursiveASTVisitor::TraverseCXXStaticCastExpr(expr
);
470 assert(!nested
.empty());
471 for (auto i
: nested
.top()) {
472 if (i
!= expr
->getSubExpr()->IgnoreParens()) {
480 bool ImplicitBoolConversion::TraverseCXXFunctionalCastExpr(
481 CXXFunctionalCastExpr
* expr
)
483 nested
.push(std::vector
<ImplicitCastExpr
const *>());
484 bool bRet
= RecursiveASTVisitor::TraverseCXXFunctionalCastExpr(expr
);
485 assert(!nested
.empty());
486 for (auto i
: nested
.top()) {
487 if (i
!= expr
->getSubExpr()->IgnoreParens()) {
495 bool ImplicitBoolConversion::TraverseConditionalOperator(
496 ConditionalOperator
* expr
)
498 nested
.push(std::vector
<ImplicitCastExpr
const *>());
499 bool bRet
= RecursiveASTVisitor::TraverseConditionalOperator(expr
);
500 assert(!nested
.empty());
501 for (auto i
: nested
.top()) {
502 if (!((i
== expr
->getTrueExpr()->IgnoreParens()
503 && (isBoolExpr(expr
->getFalseExpr()->IgnoreParenImpCasts())
504 || isExternCFunctionCallReturningInt(expr
->getFalseExpr())))
505 || (i
== expr
->getFalseExpr()->IgnoreParens()
506 && (isBoolExpr(expr
->getTrueExpr()->IgnoreParenImpCasts())
507 || isExternCFunctionCallReturningInt(
508 expr
->getTrueExpr())))
509 || (!compiler
.getLangOpts().CPlusPlus
510 && i
== expr
->getCond()->IgnoreParens())))
519 bool ImplicitBoolConversion::TraverseBinaryOperator(BinaryOperator
* expr
) {
520 switch (expr
->getOpcode()) {
528 nested
.push(std::vector
<ImplicitCastExpr
const *>());
529 bool bRet
= RecursiveASTVisitor::TraverseBinaryOperator(expr
);
530 assert(!nested
.empty());
531 for (auto i
: nested
.top()) {
532 if (!((i
== expr
->getLHS()->IgnoreParens()
534 expr
->getRHS()->IgnoreImpCasts(), i
->getSubExprAsWritten()))
535 || (i
== expr
->getRHS()->IgnoreParens()
537 expr
->getLHS()->IgnoreImpCasts(),
538 i
->getSubExprAsWritten()))))
548 nested
.push(std::vector
<ImplicitCastExpr
const *>());
549 bool bRet
= RecursiveASTVisitor::TraverseBinaryOperator(expr
);
550 // gtk-2.0/gtk/gtktogglebutton.h: struct _GtkToggleButton:
551 // guint GSEAL (active) : 1;
552 // even though <http://www.gtk.org/api/2.6/gtk/GtkToggleButton.html>:
553 // "active" gboolean : Read / Write
554 // qt5/QtGui/qaccessible.h: struct State:
555 // quint64 disabled : 1;
557 MemberExpr
const * me
= dyn_cast
<MemberExpr
>(expr
->getLHS());
559 FieldDecl
const * fd
= dyn_cast
<FieldDecl
>(me
->getMemberDecl());
560 if (fd
!= nullptr && fd
->isBitField()
561 && fd
->getBitWidthValue(compiler
.getASTContext()) == 1)
563 auto const check
= loplugin::TypeCheck(fd
->getType());
564 bExt
= check
.Typedef("guint").GlobalNamespace()
565 || check
.Typedef("quint64").GlobalNamespace();
568 assert(!nested
.empty());
569 for (auto i
: nested
.top()) {
570 if (i
!= expr
->getRHS()->IgnoreParens()
571 || !(bExt
|| isBoolExpr(expr
->getLHS())))
580 return RecursiveASTVisitor::TraverseBinaryOperator(expr
);
584 bool ImplicitBoolConversion::TraverseCompoundAssignOperator(CompoundAssignOperator
* expr
) {
585 switch (expr
->getOpcode()) {
590 nested
.push(std::vector
<ImplicitCastExpr
const *>());
591 bool bRet
= RecursiveASTVisitor::TraverseCompoundAssignOperator(expr
);
592 assert(!nested
.empty());
593 for (auto i
: nested
.top()) {
594 if (i
!= expr
->getRHS()->IgnoreParens()
595 || !isBool(expr
->getLHS()->IgnoreParens(), false))
601 if (!ignoreLocation(expr
) && isBool(expr
->getLHS(), false)
602 && !isBool(expr
->getRHS()->IgnoreParenImpCasts(), false))
605 DiagnosticsEngine::Warning
, "mix of %0 and %1 in operator %2",
606 expr
->getRHS()->getBeginLoc())
607 << expr
->getLHS()->getType()
608 << expr
->getRHS()->IgnoreParenImpCasts()->getType()
609 << expr
->getOpcodeStr()
610 << expr
->getSourceRange();
615 return RecursiveASTVisitor::TraverseCompoundAssignOperator(expr
);
619 bool ImplicitBoolConversion::TraverseInitListExpr(InitListExpr
* expr
) {
620 nested
.push(std::vector
<ImplicitCastExpr
const *>());
621 auto const e
= expr
->isSemanticForm() ? expr
: expr
->getSemanticForm();
622 auto const ret
= TraverseSynOrSemInitListExpr(e
, nullptr);
623 assert(!nested
.empty());
624 for (auto i
: nested
.top()) {
625 if (std::find(e
->begin(), e
->end(), i
) == e
->end()
626 || !i
->getType()->isSpecificBuiltinType(clang::BuiltinType::UChar
))
635 bool ImplicitBoolConversion::TraverseReturnStmt(ReturnStmt
* stmt
) {
636 nested
.push(std::vector
<ImplicitCastExpr
const *>());
637 bool bRet
= RecursiveASTVisitor::TraverseReturnStmt(stmt
);
638 Expr
const * expr
= stmt
->getRetValue();
639 if (expr
!= nullptr) {
640 ExprWithCleanups
const * ec
= dyn_cast
<ExprWithCleanups
>(expr
);
642 expr
= ec
->getSubExpr();
644 expr
= expr
->IgnoreParens();
646 assert(!nested
.empty());
647 for (auto i
: nested
.top()) {
648 if (i
!= expr
|| !bExternCIntFunctionDefinition
) {
656 bool ImplicitBoolConversion::TraverseFunctionDecl(FunctionDecl
* decl
) {
658 if (hasCLanguageLinkageType(decl
) && decl
->isThisDeclarationADefinition()) {
659 QualType t
{ decl
->getReturnType() };
660 if (t
->isSpecificBuiltinType(BuiltinType::Int
)
661 || t
->isSpecificBuiltinType(BuiltinType::UInt
))
665 TypedefType
const * t2
= t
->getAs
<TypedefType
>();
666 // cf. rtl_locale_equals (and sal_Int32 can be long):
668 && t2
->getDecl()->getNameAsString() == "sal_Int32")
675 assert(!bExternCIntFunctionDefinition
);
676 bExternCIntFunctionDefinition
= true;
678 bool bRet
= RecursiveASTVisitor::TraverseFunctionDecl(decl
);
680 bExternCIntFunctionDefinition
= false;
685 bool ImplicitBoolConversion::VisitImplicitCastExpr(
686 ImplicitCastExpr
const * expr
)
688 if (ignoreLocation(expr
)) {
691 if (isBool(compat::getSubExprAsWritten(expr
)) && !isBool(expr
)) {
692 // Ignore NoOp from 'sal_Bool' (aka 'unsigned char') to 'const unsigned
693 // char' in makeAny(b) with b of type sal_Bool:
694 if (expr
->getCastKind() == CK_NoOp
) {
697 // Ignore implicit conversions from bool to int in
699 // #define _G_STR_NONNULL(x) (x + !x)
702 // <https://gitlab.gnome.org/GNOME/glib/-/commit/48730d2b30473c5eeda2badf9a65d380304477c3>
703 // "gstrfuncs: Add back x + !x warning workaround":
704 if (auto const sub
= dyn_cast
<UnaryOperator
>(compat::getSubExprAsWritten(expr
))) {
705 if (sub
->getOpcode() == UO_LNot
) {
706 auto const l
= expr
->getBeginLoc();
707 if (compiler
.getSourceManager().isMacroBodyExpansion(l
)
708 && Lexer::getImmediateMacroName(
709 l
, compiler
.getSourceManager(), compiler
.getLangOpts())
716 if (nested
.empty()) {
719 nested
.top().push_back(expr
);
723 if (auto const sub
= dyn_cast
<ExplicitCastExpr
>(
724 compat::getSubExprAsWritten(expr
)))
726 auto const subsub
= compat::getSubExprAsWritten(sub
);
727 if (subsub
->getType().IgnoreParens() == expr
->getType().IgnoreParens()
730 // Ignore "normalizing cast" bool(b) from sal_Bool b to bool, then
731 // implicitly cast back again to sal_Bool:
732 if (dyn_cast
<CXXFunctionalCastExpr
>(sub
) != nullptr
733 && sub
->getType()->isBooleanType() && isSalBool(expr
->getType())
734 && isSalBool(subsub
->getType()))
739 DiagnosticsEngine::Warning
,
740 ("explicit conversion (%0) from %1 to %2 implicitly cast back"
743 << sub
->getCastKindName() << subsub
->getType() << sub
->getType()
744 << expr
->getType() << expr
->getSourceRange();
748 if (expr
->getType()->isBooleanType() && !isBoolExpr(expr
->getSubExpr())
751 CallExpr
const * call
= calls
.top();
753 call
->arg_begin(), call
->arg_end(),
754 [expr
](Expr
const * e
) { return expr
== e
->IgnoreParens(); }))
757 DiagnosticsEngine::Warning
,
758 "implicit conversion (%0) of call argument from %1 to %2",
760 << expr
->getCastKindName() << expr
->getSubExpr()->getType()
761 << expr
->getType() << expr
->getSourceRange();
768 bool ImplicitBoolConversion::VisitMaterializeTemporaryExpr(
769 MaterializeTemporaryExpr
const * expr
)
771 if (ignoreLocation(expr
)) {
774 if (auto const sub
= dyn_cast
<ExplicitCastExpr
>(expr
->getSubExpr())) {
775 auto const subsub
= compat::getSubExprAsWritten(sub
);
776 if (subsub
->getType().IgnoreParens() == expr
->getType().IgnoreParens()
780 DiagnosticsEngine::Warning
,
781 ("explicit conversion (%0) from %1 to %2 implicitly converted"
784 << sub
->getCastKindName() << subsub
->getType() << sub
->getType()
785 << expr
->getType() << expr
->getSourceRange();
792 bool ImplicitBoolConversion::isExternCFunctionCall(
793 CallExpr
const * expr
, FunctionProtoType
const ** functionType
)
795 assert(functionType
!= nullptr);
796 *functionType
= nullptr;
797 Decl
const * d
= expr
->getCalleeDecl();
799 FunctionDecl
const * fd
= dyn_cast
<FunctionDecl
>(d
);
801 clang::PointerType
const * pt
= fd
->getType()
802 ->getAs
<clang::PointerType
>();
803 QualType
t2(pt
== nullptr ? fd
->getType() : pt
->getPointeeType());
804 *functionType
= t2
->getAs
<FunctionProtoType
>();
806 *functionType
!= nullptr || !compiler
.getLangOpts().CPlusPlus
807 || (fd
->getBuiltinID() != Builtin::NotBuiltin
808 && isa
<FunctionNoProtoType
>(t2
)));
809 // __builtin_*s have no proto type?
810 return fd
->isExternC()
811 || compiler
.getSourceManager().isInExternCSystemHeader(
814 VarDecl
const * vd
= dyn_cast
<VarDecl
>(d
);
816 clang::PointerType
const * pt
= vd
->getType()
817 ->getAs
<clang::PointerType
>();
819 = ((pt
== nullptr ? vd
->getType() : pt
->getPointeeType())
820 ->getAs
<FunctionProtoType
>());
821 return vd
->isExternC();
827 bool ImplicitBoolConversion::isExternCFunctionCallReturningInt(
830 CallExpr
const * e
= dyn_cast
<CallExpr
>(expr
->IgnoreParenImpCasts());
831 FunctionProtoType
const * t
;
832 return e
!= nullptr && e
->getType()->isSpecificBuiltinType(BuiltinType::Int
)
833 && isExternCFunctionCall(e
, &t
);
836 void ImplicitBoolConversion::checkCXXConstructExpr(
837 CXXConstructExpr
const * expr
)
839 assert(!nested
.empty());
840 for (auto i
: nested
.top()) {
841 auto j
= std::find_if(
842 expr
->arg_begin(), expr
->arg_end(),
843 [&i
](Expr
const * e
) {
844 return i
== ignoreParenAndTemporaryMaterialization(e
);
846 if (j
!= expr
->arg_end()) {
847 TemplateSpecializationType
const * t1
= expr
->getType()->
848 getAs
<TemplateSpecializationType
>();
851 if (i
->getType()->isSpecificBuiltinType(clang::BuiltinType::UChar
)) {
855 SubstTemplateTypeParmType
const * t2
= nullptr;
856 CXXConstructorDecl
const * d
= expr
->getConstructor();
857 if (d
->getNumParams() == expr
->getNumArgs()) { //TODO: better check
858 t2
= getAsSubstTemplateTypeParmType(
859 d
->getParamDecl(j
- expr
->arg_begin())->getType()
860 .getNonReferenceType());
863 TemplateDecl
const * td
864 = t1
->getTemplateName().getAsTemplateDecl();
866 TemplateParameterList
const * ps
867 = td
->getTemplateParameters();
869 ps
->begin(), ps
->end(),
870 compat::getReplacedParameter(t2
));
871 if (k
!= ps
->end()) {
872 auto const args
= t1
->template_arguments();
873 if (ps
->size() == args
.size()) { //TODO
874 TemplateArgument
const & arg
= args
[
876 if (arg
.getKind() == TemplateArgument::Type
877 && (loplugin::TypeCheck(arg
.getAsType())
892 void ImplicitBoolConversion::reportWarning(ImplicitCastExpr
const * expr
) {
893 if (compiler
.getLangOpts().CPlusPlus
) {
894 if (expr
->getCastKind() == CK_ConstructorConversion
) {
895 auto const t1
= expr
->getType();
896 if (auto const t2
= t1
->getAs
<TemplateSpecializationType
>()) {
897 auto const args
= t2
->template_arguments();
898 assert(args
.size() >= 1);
899 auto const a
= args
[0];
900 if (a
.getKind() == TemplateArgument::Type
&& a
.getAsType()->isBooleanType()
901 && (loplugin::TypeCheck(t1
).TemplateSpecializationClass()
902 .ClassOrStruct("atomic").StdNamespace()))
909 DiagnosticsEngine::Warning
,
910 "implicit conversion (%0) from %1 to %2", expr
->getBeginLoc())
911 << expr
->getCastKindName() << expr
->getSubExprAsWritten()->getType()
912 << expr
->getType() << expr
->getSourceRange();
916 loplugin::Plugin::Registration
<ImplicitBoolConversion
> X(
917 "implicitboolconversion");
921 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */