#include namespace clice::index { /// A bit field enum to describe the kind of relation between two symbols. struct RelationKind : support::Enum { using Enum::Enum; enum Kind : uint32_t { Invalid, Declaration, Definition, Reference, // Write Relation. Read, Write, Interface, Implementation, /// When target is a type definition of source, source is possible type or constructor. TypeDefinition, /// When target is a base class of source. Base, /// When target is a derived class of source. Derived, /// When target is a constructor of source. Constructor, /// When target is a destructor of source. Destructor, // When target is a caller of source. Caller, // When target is a callee of source. Callee, }; }; template struct Ref { std::uint32_t offset = std::numeric_limits::max(); bool isValid() const { return offset != std::numeric_limits::max(); } bool isInvalid() const { return !isValid(); } explicit operator bool () const { return isValid(); } friend constexpr auto operator<=> (const Ref& lhs, const Ref& rhs) = default; }; struct LocationRef : Ref {}; struct SymOrLocRef : Ref {}; struct Relation { /// The kind of the relation. RelationKind kind; /// The index of location in `Index::locations`. LocationRef location; /// Additional information based on the `Relation::kind`. For `Declaration` and `Definition`, /// this is the source range of the whole entity(`Relation::location` is just the range of /// symbol name). For kinds whose target symbol is different from the source symbol, e.g. /// `TypeDefinition` and `Base`, this is the index of target symbol in `Index::symbols`. SymOrLocRef symOrLoc; static bool isSymbol(const Relation& relation) { auto kind = relation.kind; return kind & RelationKind::Interface || kind & RelationKind::Implementation || kind & RelationKind::TypeDefinition || kind & RelationKind::Base || kind & RelationKind::Derived || kind & RelationKind::Constructor || kind & RelationKind::Destructor || kind & RelationKind::Caller || kind & RelationKind::Callee; } }; } // namespace clice::index