summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/check.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/check.hxx')
-rw-r--r--compilerplugins/clang/check.hxx207
1 files changed, 207 insertions, 0 deletions
diff --git a/compilerplugins/clang/check.hxx b/compilerplugins/clang/check.hxx
new file mode 100644
index 000000000000..999a3185d73f
--- /dev/null
+++ b/compilerplugins/clang/check.hxx
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_COMPILERPLUGINS_CLANG_CHECK_HXX
+#define INCLUDED_COMPILERPLUGINS_CLANG_CHECK_HXX
+
+#include <cstddef>
+
+#include <clang/AST/DeclBase.h>
+#include <clang/AST/Decl.h>
+#include <clang/AST/Type.h>
+#include <clang/Basic/OperatorKinds.h>
+
+namespace loplugin {
+
+class ContextCheck;
+class TerminalCheck;
+
+namespace detail {
+
+template<std::size_t N> ContextCheck checkRecordDecl(
+ clang::Decl const * decl, clang::TagTypeKind tag, char const (& id)[N]);
+
+}
+
+class TypeCheck {
+public:
+ explicit TypeCheck(clang::QualType type): type_(type) {}
+
+ explicit operator bool() const { return !type_.isNull(); }
+
+ TypeCheck Const() const;
+
+ TerminalCheck Char() const;
+
+ TypeCheck LvalueReference() const;
+
+ template<std::size_t N> inline ContextCheck Class(char const (& id)[N])
+ const;
+
+ TypeCheck NotSubstTemplateTypeParmType() const;
+
+private:
+ TypeCheck() = default;
+
+ clang::QualType const type_;
+};
+
+class DeclCheck {
+public:
+ explicit DeclCheck(clang::Decl const * decl): decl_(decl) {}
+
+ explicit operator bool() const { return decl_ != nullptr; }
+
+ template<std::size_t N> inline ContextCheck Class(char const (& id)[N])
+ const;
+
+ template<std::size_t N> inline ContextCheck Struct(char const (& id)[N])
+ const;
+
+ template<std::size_t N> inline ContextCheck Function(char const (& id)[N])
+ const;
+
+ ContextCheck Operator(clang::OverloadedOperatorKind op) const;
+
+private:
+ clang::Decl const * const decl_;
+};
+
+class ContextCheck {
+public:
+ explicit operator bool() const { return context_ != nullptr; }
+
+ TerminalCheck GlobalNamespace() const;
+
+ template<std::size_t N> inline ContextCheck Namespace(
+ char const (& id)[N]) const;
+
+ TerminalCheck StdNamespace() const;
+
+ ContextCheck AnonymousNamespace() const;
+
+ template<std::size_t N> inline ContextCheck Class(char const (& id)[N])
+ const;
+
+ template<std::size_t N> inline ContextCheck Struct(char const (& id)[N])
+ const;
+
+private:
+ friend DeclCheck;
+ friend TypeCheck;
+ template<std::size_t N> friend ContextCheck detail::checkRecordDecl(
+ clang::Decl const * decl, clang::TagTypeKind tag, char const (& id)[N]);
+
+ explicit ContextCheck(clang::DeclContext const * context = nullptr):
+ context_(context) {}
+
+ clang::DeclContext const * const context_;
+};
+
+class TerminalCheck {
+public:
+ explicit operator bool() const { return satisfied_; }
+
+private:
+ friend ContextCheck;
+ friend TypeCheck;
+
+ explicit TerminalCheck(bool satisfied): satisfied_(satisfied) {}
+
+ bool const satisfied_;
+};
+
+namespace detail {
+
+template<std::size_t N> ContextCheck checkRecordDecl(
+ clang::Decl const * decl, clang::TagTypeKind tag, char const (& id)[N])
+{
+ auto r = llvm::dyn_cast_or_null<clang::RecordDecl>(decl);
+ if (r != nullptr && r->getTagKind() == tag) {
+ auto const i = r->getIdentifier();
+ if (i != nullptr && i->isStr(id)) {
+ return ContextCheck(r->getDeclContext());
+ }
+ }
+ return ContextCheck();
+}
+
+}
+
+template<std::size_t N> ContextCheck TypeCheck::Class(char const (& id)[N])
+ const
+{
+ if (!type_.isNull()) {
+ auto const t = type_->getAs<clang::RecordType>();
+ if (t != nullptr) {
+ return detail::checkRecordDecl(t->getDecl(), clang::TTK_Class, id);
+ }
+ }
+ return ContextCheck();
+}
+
+template<std::size_t N> ContextCheck DeclCheck::Class(char const (& id)[N])
+ const
+{
+ return detail::checkRecordDecl(decl_, clang::TTK_Class, id);
+}
+
+template<std::size_t N> ContextCheck DeclCheck::Struct(char const (& id)[N])
+ const
+{
+ return detail::checkRecordDecl(decl_, clang::TTK_Struct, id);
+}
+
+template<std::size_t N> ContextCheck DeclCheck::Function(char const (& id)[N])
+ const
+{
+ auto f = llvm::dyn_cast_or_null<clang::FunctionDecl>(decl_);
+ if (f != nullptr) {
+ auto const i = f->getIdentifier();
+ if (i != nullptr && i->isStr(id)) {
+ return ContextCheck(f->getDeclContext());
+ }
+ }
+ return ContextCheck();
+}
+
+template<std::size_t N> ContextCheck ContextCheck::Namespace(
+ char const (& id)[N]) const
+{
+ if (context_) {
+ auto n = llvm::dyn_cast<clang::NamespaceDecl>(context_);
+ if (n != nullptr) {
+ auto const i = n->getIdentifier();
+ if (i != nullptr && i->isStr(id)) {
+ return ContextCheck(n->getParent());
+ }
+ }
+ }
+ return ContextCheck();
+}
+
+template<std::size_t N> ContextCheck ContextCheck::Class(char const (& id)[N])
+ const
+{
+ return detail::checkRecordDecl(
+ llvm::dyn_cast_or_null<clang::Decl>(context_), clang::TTK_Class, id);
+}
+
+template<std::size_t N> ContextCheck ContextCheck::Struct(char const (& id)[N])
+ const
+{
+ return detail::checkRecordDecl(
+ llvm::dyn_cast_or_null<clang::Decl>(context_), clang::TTK_Struct, id);
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */