diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2017-01-05 09:17:23 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2017-01-05 09:17:47 +0100 |
commit | ad9cfbcf02b74b1d1ca9cc5d51e5f3777cb9eab9 (patch) | |
tree | dfe2a07e67bc5b1c48d8bd81ff092919f37270e3 /compilerplugins | |
parent | 5af78ee8dfcb05319ec3a8f9df9c12b9a2b30539 (diff) |
Don't exclude a var from loplugin:salbool merely because of use in >>=
Change-Id: I1b8a3dfa1dc6b351ab0903a74eae19dfa6d0888d
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/salbool.cxx | 104 |
1 files changed, 71 insertions, 33 deletions
diff --git a/compilerplugins/clang/salbool.cxx b/compilerplugins/clang/salbool.cxx index 2da581111264..bdb56eae62be 100644 --- a/compilerplugins/clang/salbool.cxx +++ b/compilerplugins/clang/salbool.cxx @@ -70,37 +70,72 @@ OverrideKind getOverrideKind(FunctionDecl const * decl) { return OverrideKind::MAYBE; } +enum class BoolOverloadKind { No, Yes, CheckNext }; + +BoolOverloadKind isBoolOverloadOf( + FunctionDecl const * f, FunctionDecl const * decl, bool mustBeDeleted) +{ + if (!mustBeDeleted || f->isDeleted()) { + unsigned n = decl->getNumParams(); + if (f->getNumParams() == n) { + bool hasSB = false; + for (unsigned i = 0; i != n; ++i) { + QualType t1 { decl->getParamDecl(i)->getType() }; + bool isSB = isSalBool(t1); + bool isSBRef = !isSB && t1->isReferenceType() + && isSalBool(t1.getNonReferenceType()); + QualType t2 { f->getParamDecl(i)->getType() }; + if (!(isSB + ? t2->isBooleanType() + : isSBRef + ? (t2->isReferenceType() + && t2.getNonReferenceType()->isBooleanType()) + : t2.getCanonicalType() == t1.getCanonicalType())) + { + return BoolOverloadKind::CheckNext; + } + hasSB |= isSB || isSBRef; + } + return hasSB ? BoolOverloadKind::Yes : BoolOverloadKind::No; + // cheaply protect against the case where decl would have no + // sal_Bool parameters at all and would match itself + } + } + return BoolOverloadKind::CheckNext; +} + //TODO: current implementation is not at all general, just tests what we // encounter in practice: bool hasBoolOverload(FunctionDecl const * decl, bool mustBeDeleted) { - unsigned n = decl->getNumParams(); - auto res = decl->getDeclContext()->lookup(decl->getDeclName()); + auto ctx = decl->getDeclContext(); + if (!ctx->isLookupContext()) { + return false; + } + auto res = ctx->lookup(decl->getDeclName()); for (auto d = res.begin(); d != res.end(); ++d) { - FunctionDecl const * f = dyn_cast<FunctionDecl>(*d); - if (f != nullptr && (!mustBeDeleted || f->isDeleted())) { - if (f->getNumParams() == n) { - bool hasSB = false; - for (unsigned i = 0; i != n; ++i) { - QualType t1 { decl->getParamDecl(i)->getType() }; - bool isSB = isSalBool(t1); - bool isSBRef = !isSB && t1->isReferenceType() - && isSalBool(t1.getNonReferenceType()); - QualType t2 { f->getParamDecl(i)->getType() }; - if (!(isSB - ? t2->isBooleanType() - : isSBRef - ? (t2->isReferenceType() - && t2.getNonReferenceType()->isBooleanType()) - : t2 == t1)) - { - goto next; + if (auto f = dyn_cast<FunctionDecl>(*d)) { + switch (isBoolOverloadOf(f, decl, mustBeDeleted)) { + case BoolOverloadKind::No: + return false; + case BoolOverloadKind::Yes: + return true; + case BoolOverloadKind::CheckNext: + break; + } + } else if (auto ftd = dyn_cast<FunctionTemplateDecl>(*d)) { + for (auto f: ftd->specializations()) { + if (f->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + { + switch (isBoolOverloadOf(f, decl, mustBeDeleted)) { + case BoolOverloadKind::No: + return false; + case BoolOverloadKind::Yes: + return true; + case BoolOverloadKind::CheckNext: + break; } - hasSB |= isSB || isSBRef; } - return hasSB; - // cheaply protect against the case where decl would have no - // sal_Bool parameters at all and would match itself - next:; } } } @@ -226,14 +261,17 @@ bool SalBool::VisitCallExpr(CallExpr * expr) { if (d != nullptr) { FunctionDecl const * fd = dyn_cast<FunctionDecl>(d); if (fd != nullptr) { - PointerType const * pt = fd->getType()->getAs<PointerType>(); - QualType t2(pt == nullptr ? fd->getType() : pt->getPointeeType()); - ft = t2->getAs<FunctionProtoType>(); - assert( - ft != nullptr || !compiler.getLangOpts().CPlusPlus - || (fd->getBuiltinID() != Builtin::NotBuiltin - && isa<FunctionNoProtoType>(t2))); - // __builtin_*s have no proto type? + if (!hasBoolOverload(fd, false)) { + PointerType const * pt = fd->getType()->getAs<PointerType>(); + QualType t2( + pt == nullptr ? fd->getType() : pt->getPointeeType()); + ft = t2->getAs<FunctionProtoType>(); + assert( + ft != nullptr || !compiler.getLangOpts().CPlusPlus + || (fd->getBuiltinID() != Builtin::NotBuiltin + && isa<FunctionNoProtoType>(t2))); + // __builtin_*s have no proto type? + } } else { VarDecl const * vd = dyn_cast<VarDecl>(d); if (vd != nullptr) { |