//===- tapi/Core/XPI.h - TAPI XPI -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// Defines XPI - API, SPI, etc /// //===----------------------------------------------------------------------===// #ifndef TAPI_CORE_XPI_H #define TAPI_CORE_XPI_H #include "Architecture.h" #include "ArchitectureSet.h" #include "AvailabilityInfo.h" #include "LLVM.h" #include "STLExtras.h" #include "Defines.h" #include "Symbol.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/Support/Allocator.h" #include #include TAPI_NAMESPACE_INTERNAL_BEGIN class ObjCClass; class ObjCContainer; class XPISet; using SymbolFlags = tapi::v1::SymbolFlags; /// Helper method to create the symbol flags from the XPI flags. inline SymbolFlags operator|=(SymbolFlags &lhs, const SymbolFlags &rhs) noexcept { lhs = static_cast(static_cast(lhs) | static_cast(rhs)); return lhs; } /// The different XPI kinds. enum class XPIKind : unsigned { GlobalSymbol, ObjectiveCClass, ObjectiveCClassEHType, ObjectiveCInstanceVariable, ObjCSelector, ObjCCategory, ObjCProtocol, }; /// The XPI access permissions/visibility. enum class XPIAccess : unsigned { Unknown, Exported, Public, Private, Project, Internal, }; class XPI { protected: /// Construct an XPI - the constructor should only be called by a /// sub-class. XPI(XPIKind kind, StringRef name, XPIAccess access, SymbolFlags flags = SymbolFlags::None) : _name(name), _kind(kind), _access(access), _flags(flags) {} /// Construct an XPI - the constructor should only be called by a /// sub-class. XPI(XPIKind kind, StringRef name, XPIAccess access, Architecture arch, AvailabilityInfo &info) : XPI(kind, name, access) { addAvailabilityInfo(arch, info); if (!info._unavailable) _archs.set(arch); } public: bool isExportedSymbol() const; StringRef getName() const { return _name; } XPIKind getKind() const { return _kind; } XPIAccess getAccess() const { return _access; } void setAccess(XPIAccess access) { _access = access; } bool updateAccess(XPIAccess access) { if (access == XPIAccess::Unknown) return true; if (getAccess() == XPIAccess::Unknown) { setAccess(access); return true; } // XPIAccess Public and Private are for header declaration only. // It is fine to re-declare the public XPI in the private header again and // the final XPIAccess type should be public. if (getAccess() == XPIAccess::Public && access == XPIAccess::Private) return true; if (getAccess() == XPIAccess::Private && access == XPIAccess::Public) { setAccess(access); return true; } return getAccess() == access; } bool isWeakDefined() const { return (_flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined; } bool isWeakReferenced() const { return (_flags & SymbolFlags::WeakReferenced) == SymbolFlags::WeakReferenced; } bool isThreadLocalValue() const { return (_flags & SymbolFlags::ThreadLocalValue) == SymbolFlags::ThreadLocalValue; } SymbolFlags getSymbolFlags() const { return _flags; } void addAvailabilityInfo(Architecture arch, const AvailabilityInfo info = AvailabilityInfo(), bool NoOverwrite = false) { auto it = find_if(_availability, [arch](const std::pair &avail) { return arch == avail.first; }); if (it != _availability.end()) { if (NoOverwrite && !it->second.isDefault()) it->second = info; if (!info._unavailable && info._obsoleted.empty()) { it->second._unavailable = false; _archs.set(arch); } return; } _availability.emplace_back(arch, info); if (!info._unavailable && info._obsoleted.empty()) _archs.set(arch); } const llvm::SmallVectorImpl> & getAvailabilityInfo() const { return _availability; } llvm::Optional getAvailabilityInfo(Architecture arch) const { auto it = find_if(_availability, [arch](const std::pair &avail) { return arch == avail.first; }); if (it != _availability.end()) return it->second; return llvm::None; } ArchitectureSet getArchitectures() const { return _archs; } bool hasArch(Architecture arch) const { return _archs.has(arch); } bool isAvailable() const { return _archs.count() != 0; } bool isUnavailable() const { return _archs.count() == 0; } bool isObsolete() const { for (const auto &avail : _availability) if (avail.second._obsoleted.empty()) return false; return true; } std::string getPrettyName(bool demangle = false) const; std::string getAnnotatedName(bool demangle = false) const; void print(raw_ostream &os) const; bool operator<(const XPI &other) const { return std::tie(_kind, _name) < std::tie(other._kind, other._name); } private: llvm::SmallVector, 4> _availability{}; StringRef _name; ArchitectureSet _archs{}; protected: /// The kind of xpi. XPIKind _kind; /// The access permission/visibility of this xpi. XPIAccess _access; /// Hoisted GlobalSymbol flags. SymbolFlags _flags; }; inline raw_ostream &operator<<(raw_ostream &os, const XPI &xpi) { xpi.print(os); return os; } class GlobalSymbol : public XPI { private: GlobalSymbol(StringRef name, XPIAccess access, SymbolFlags flags) : XPI(XPIKind::GlobalSymbol, name, access, flags) {} public: static GlobalSymbol *create(llvm::BumpPtrAllocator &A, StringRef name, XPIAccess access, SymbolFlags flags = SymbolFlags::None); static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::GlobalSymbol; } }; class ObjCClassEHType : public XPI { private: ObjCClassEHType(StringRef name, XPIAccess access) : XPI(XPIKind::ObjectiveCClassEHType, name, access) {} public: static ObjCClassEHType *create(llvm::BumpPtrAllocator &A, StringRef name, XPIAccess access); static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::ObjectiveCClassEHType; } }; class ObjCInstanceVariable : public XPI { private: ObjCInstanceVariable(StringRef name, XPIAccess access) : XPI(XPIKind::ObjectiveCInstanceVariable, name, access) {} public: static ObjCInstanceVariable *create(llvm::BumpPtrAllocator &A, StringRef name, XPIAccess access); static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::ObjectiveCInstanceVariable; } }; class ObjCSelector : public XPI { private: bool _isInstanceMethod; bool _isDynamic; bool _isDerivedFromProtocol; ObjCSelector(StringRef name, bool isInstanceMethod, bool isDynamic, XPIAccess access, bool isDerivedFromProtocol) : XPI(XPIKind::ObjCSelector, name, access), _isInstanceMethod(isInstanceMethod), _isDynamic(isDynamic), _isDerivedFromProtocol(isDerivedFromProtocol) {} public: static ObjCSelector *create(llvm::BumpPtrAllocator &A, StringRef name, bool isInstanceMethod, bool isDynamic, XPIAccess access, bool isDerivedFromProtocol = false); bool isInstanceMethod() const { return _isInstanceMethod; } bool isDynamic() const { return _isDynamic; } bool isDerivedFromProtocol() const { return _isDerivedFromProtocol; } static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::ObjCSelector; } }; class ObjCContainer : public XPI { public: ObjCContainer(XPIKind kind, StringRef name, XPIAccess access) : XPI(kind, name, access) {} static bool classof(const XPI *xpi) { auto K = xpi->getKind(); return K == XPIKind::ObjCProtocol || K == XPIKind::ObjectiveCClass || K == XPIKind::ObjCCategory; } void addSelector(const ObjCSelector *selector); const ObjCSelector *findSelector(StringRef name, bool isInstanceMethod = false) const; using const_selector_range = llvm::iterator_range< SmallVectorImpl::const_iterator>; const_selector_range selectors() const { return _selectors; } private: llvm::SmallVector _selectors; }; class ObjCProtocol : public ObjCContainer { private: ObjCProtocol(StringRef name, XPIAccess access) : ObjCContainer(XPIKind::ObjCProtocol, name, access) {} public: static ObjCProtocol *create(llvm::BumpPtrAllocator &A, StringRef name, XPIAccess access); static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::ObjCProtocol; } }; class ObjCCategory : public ObjCContainer { private: ObjCCategory(ObjCClass *baseClass, StringRef name, XPIAccess access) : ObjCContainer(XPIKind::ObjCCategory, name, access), _baseClass(baseClass) {} public: static ObjCCategory *create(llvm::BumpPtrAllocator &A, ObjCClass *baseClass, StringRef name, XPIAccess access); static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::ObjCCategory; } const ObjCClass *getBaseClass() const { return _baseClass; } private: const ObjCClass *_baseClass; }; class ObjCClass : public ObjCContainer { private: ObjCClass(StringRef name, XPIAccess access) : ObjCContainer(XPIKind::ObjectiveCClass, name, access), _superClass(nullptr) {} public: static ObjCClass *create(llvm::BumpPtrAllocator &A, StringRef name, XPIAccess access); static bool classof(const XPI *xpi) { return xpi->getKind() == XPIKind::ObjectiveCClass; } bool updateSuperClass(ObjCClass *superClass) { if (superClass == nullptr) return true; if (_superClass == nullptr) { _superClass = superClass; return true; } return _superClass == superClass; } const ObjCClass *getSuperClass() const { return _superClass; } void addCategory(const ObjCCategory *category); using const_category_range = llvm::iterator_range< llvm::SmallVectorImpl::const_iterator>; const_category_range categories() const { return _categories; } private: llvm::SmallVector _categories; const ObjCClass *_superClass; }; TAPI_NAMESPACE_INTERNAL_END #endif // TAPI_CORE_XPI_H