/* -*- 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 #include #include #include #include namespace loplugin { class ContextCheck; class TerminalCheck; namespace detail { template ContextCheck checkRecordDecl( clang::Decl const * decl, clang::TagTypeKind tag, char const (& id)[N]); } class TypeCheck { public: explicit TypeCheck(clang::QualType type): type_(type) {} explicit TypeCheck(clang::TypeDecl const * decl): type_(decl->getTypeForDecl(), 0) {} explicit operator bool() const { return !type_.isNull(); } TypeCheck NonConst() const; TypeCheck NonConstVolatile() const; TypeCheck Const() const; TypeCheck Volatile() const; TypeCheck ConstVolatile() const; TerminalCheck Void() const; TerminalCheck Char() const; TerminalCheck AnyBoolean() const; TypeCheck Pointer() const; TerminalCheck Enum() const; TypeCheck LvalueReference() const; template inline ContextCheck Class(char const (& id)[N]) const; template inline ContextCheck Struct(char const (& id)[N]) const; TypeCheck Typedef() const; template inline ContextCheck Typedef(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 inline ContextCheck Class(char const (& id)[N]) const; template inline ContextCheck Struct(char const (& id)[N]) const; template inline ContextCheck Union(char const (& id)[N]) const; template inline ContextCheck Function(char const (& id)[N]) const; ContextCheck Operator(clang::OverloadedOperatorKind op) const; template inline ContextCheck Var(char const (& id)[N]) const; ContextCheck MemberFunction() const; private: clang::Decl const * const decl_; }; class ContextCheck { public: explicit operator bool() const { return context_ != nullptr; } TerminalCheck GlobalNamespace() const; template inline ContextCheck Namespace( char const (& id)[N]) const; TerminalCheck StdNamespace() const; ContextCheck AnonymousNamespace() const; template inline ContextCheck Class(char const (& id)[N]) const; template inline ContextCheck Struct(char const (& id)[N]) const; private: friend DeclCheck; friend TypeCheck; template 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 ContextCheck checkRecordDecl( clang::Decl const * decl, clang::TagTypeKind tag, char const (& id)[N]) { auto r = llvm::dyn_cast_or_null(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 ContextCheck TypeCheck::Class(char const (& id)[N]) const { if (!type_.isNull()) { auto const t = type_->getAs(); if (t != nullptr) { return detail::checkRecordDecl(t->getDecl(), clang::TTK_Class, id); } } return ContextCheck(); } template ContextCheck TypeCheck::Struct(char const (& id)[N]) const { if (!type_.isNull()) { auto const t = type_->getAs(); if (t != nullptr) { return detail::checkRecordDecl(t->getDecl(), clang::TTK_Struct, id); } } return ContextCheck(); } template ContextCheck TypeCheck::Typedef(char const (& id)[N]) const { if (!type_.isNull()) { if (auto const t = type_->getAs()) { auto const d = t->getDecl(); auto const i = d->getIdentifier(); assert(i != nullptr); if (i->isStr(id)) { return ContextCheck(d->getDeclContext()); } } } return ContextCheck(); } template ContextCheck DeclCheck::Class(char const (& id)[N]) const { return detail::checkRecordDecl(decl_, clang::TTK_Class, id); } template ContextCheck DeclCheck::Struct(char const (& id)[N]) const { return detail::checkRecordDecl(decl_, clang::TTK_Struct, id); } template ContextCheck DeclCheck::Union(char const (& id)[N]) const { return detail::checkRecordDecl(decl_, clang::TTK_Union, id); } template ContextCheck DeclCheck::Function(char const (& id)[N]) const { auto f = llvm::dyn_cast_or_null(decl_); if (f != nullptr) { auto const i = f->getIdentifier(); if (i != nullptr && i->isStr(id)) { return ContextCheck(f->getDeclContext()); } } return ContextCheck(); } template ContextCheck DeclCheck::Var(char const (& id)[N]) const { auto f = llvm::dyn_cast_or_null(decl_); if (f != nullptr) { auto const i = f->getIdentifier(); if (i != nullptr && i->isStr(id)) { return ContextCheck(f->getDeclContext()); } } return ContextCheck(); } template ContextCheck ContextCheck::Namespace( char const (& id)[N]) const { if (context_) { auto n = llvm::dyn_cast(context_); if (n != nullptr) { auto const i = n->getIdentifier(); if (i != nullptr && i->isStr(id)) { return ContextCheck(n->getParent()); } } } return ContextCheck(); } template ContextCheck ContextCheck::Class(char const (& id)[N]) const { return detail::checkRecordDecl( llvm::dyn_cast_or_null(context_), clang::TTK_Class, id); } template ContextCheck ContextCheck::Struct(char const (& id)[N]) const { return detail::checkRecordDecl( llvm::dyn_cast_or_null(context_), clang::TTK_Struct, id); } bool isExtraWarnUnusedType(clang::QualType type); bool isOkToRemoveArithmeticCast( clang::ASTContext & context, clang::QualType t1, clang::QualType t2, const clang::Expr* subExpr); } #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */