diff options
Diffstat (limited to 'compilerplugins/clang/check.cxx')
-rw-r--r-- | compilerplugins/clang/check.cxx | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/compilerplugins/clang/check.cxx b/compilerplugins/clang/check.cxx index 003224a21ba1..524885ce16e4 100644 --- a/compilerplugins/clang/check.cxx +++ b/compilerplugins/clang/check.cxx @@ -13,6 +13,7 @@ #include <clang/AST/DeclTemplate.h> #include "check.hxx" +#include "compat.hxx" namespace loplugin { @@ -133,6 +134,16 @@ TypeCheck TypeCheck::Pointer() const { return TypeCheck(); } +TypeCheck TypeCheck::MemberPointerOf() const { + if (!type_.isNull()) { + auto const t = type_->getAs<clang::MemberPointerType>(); + if (t != nullptr) { + return TypeCheck(compat::getClass(t)); + } + } + return TypeCheck(); +} + TerminalCheck TypeCheck::Enum() const { if (!type_.isNull()) { auto const t = type_->getAs<clang::EnumType>(); @@ -191,7 +202,7 @@ namespace { bool isGlobalNamespace(clang::DeclContext const * context) { assert(context != nullptr); - return (context->isLookupContext() ? context : context->getLookupParent())->isTranslationUnit(); + return context->getEnclosingNamespaceContext()->isTranslationUnit(); } } @@ -202,7 +213,7 @@ TerminalCheck ContextCheck::GlobalNamespace() const { TerminalCheck ContextCheck::StdNamespace() const { return TerminalCheck( - context_ != nullptr && context_->isStdNamespace()); + context_ != nullptr && lookThroughLinkageSpec()->isStdNamespace()); } namespace { @@ -224,15 +235,22 @@ bool isStdOrNestedNamespace(clang::DeclContext const * context) { } TerminalCheck ContextCheck::StdOrNestedNamespace() const { - return TerminalCheck(context_ != nullptr && isStdOrNestedNamespace(context_)); + return TerminalCheck(context_ != nullptr && isStdOrNestedNamespace(lookThroughLinkageSpec())); } ContextCheck ContextCheck::AnonymousNamespace() const { - auto n = llvm::dyn_cast_or_null<clang::NamespaceDecl>(context_); + auto n = llvm::dyn_cast_or_null<clang::NamespaceDecl>(lookThroughLinkageSpec()); return ContextCheck( n != nullptr && n->isAnonymousNamespace() ? n->getParent() : nullptr); } +clang::DeclContext const * ContextCheck::lookThroughLinkageSpec() const { + if (context_ != nullptr && context_->getDeclKind() == clang::Decl::LinkageSpec) { + return context_->getParent(); + } + return context_; +} + namespace { bool BaseCheckNotSomethingInterestingSubclass(const clang::CXXRecordDecl *BaseDefinition) { @@ -357,27 +375,47 @@ bool isOkToRemoveArithmeticCast( } -static bool BaseCheckNotSubclass(const clang::CXXRecordDecl *BaseDefinition, void *p) { - if (!BaseDefinition) - return true; +static bool BaseCheckSubclass(const clang::CXXRecordDecl *BaseDefinition, void *p) { + assert(BaseDefinition != nullptr); auto const & base = *static_cast<const DeclChecker *>(p); if (base(BaseDefinition)) { - return false; + return true; } - return true; + return false; +} + +bool forAnyBase( + clang::CXXRecordDecl const * decl, clang::CXXRecordDecl::ForallBasesCallback matches) +{ + // Based on the implementation of clang::CXXRecordDecl::forallBases in LLVM's + // clang/lib/AST/CXXInheritance.cpp: + for (auto const & i: decl->bases()) { + auto const t = i.getType()->getAs<clang::RecordType>(); + if (t == nullptr) { + return false; + } + auto const b = llvm::cast_or_null<clang::CXXRecordDecl>(t->getDecl()->getDefinition()); + if (b == nullptr || (b->isDependentContext() && !b->isCurrentInstantiation(decl))) { + return false; + } + if (matches(b) || forAnyBase(b, matches)) { + return true; + } + } + return false; } -bool isDerivedFrom(const clang::CXXRecordDecl *decl, DeclChecker base) { +bool isDerivedFrom(const clang::CXXRecordDecl *decl, DeclChecker base, bool checkSelf) { if (!decl) return false; - if (base(decl)) + if (checkSelf && base(decl)) return true; if (!decl->hasDefinition()) { return false; } - if (!decl->forallBases( + if (forAnyBase(decl, [&base](const clang::CXXRecordDecl *BaseDefinition) -> bool - { return BaseCheckNotSubclass(BaseDefinition, &base); })) + { return BaseCheckSubclass(BaseDefinition, &base); })) { return true; } |