summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/check.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/check.cxx')
-rw-r--r--compilerplugins/clang/check.cxx64
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;
}