blob: e7a3decc85f7beaa120b7ded1d8b38e5251bad1d [file] [log] [blame]
//===- 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 <map>
#include <utility>
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<SymbolFlags>(static_cast<unsigned>(lhs) |
static_cast<unsigned>(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<Architecture, AvailabilityInfo> &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<std::pair<Architecture, AvailabilityInfo>> &
getAvailabilityInfo() const {
return _availability;
}
llvm::Optional<AvailabilityInfo>
getAvailabilityInfo(Architecture arch) const {
auto it =
find_if(_availability,
[arch](const std::pair<Architecture, AvailabilityInfo> &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<std::pair<Architecture, AvailabilityInfo>, 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 ObjCSelector *>::const_iterator>;
const_selector_range selectors() const { return _selectors; }
private:
llvm::SmallVector<const ObjCSelector *, 8> _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 ObjCCategory *>::const_iterator>;
const_category_range categories() const { return _categories; }
private:
llvm::SmallVector<const ObjCCategory *, 4> _categories;
const ObjCClass *_superClass;
};
TAPI_NAMESPACE_INTERNAL_END
#endif // TAPI_CORE_XPI_H