// Copyright 2017-2018 ccls Authors // SPDX-License-Identifier: Apache-2.0 #pragma once #include "lsp.hh" #include "position.hh" #include "serializer.hh" #include "utils.hh" #include #include #include #include #include #include #include #include namespace std { template <> struct hash { std::size_t operator()(llvm::sys::fs::UniqueID ID) const { size_t ret = ID.getDevice(); ccls::hash_combine(ret, ID.getFile()); return ret; } }; } // namespace std namespace ccls { using Usr = uint64_t; // The order matters. In FindSymbolsAtLocation, we want Var/Func ordered in // front of others. enum class Kind : uint8_t { Invalid, File, Type, Func, Var }; REFLECT_UNDERLYING_B(Kind); enum class Role : uint16_t { None = 0, Declaration = 1 << 0, Definition = 1 << 1, Reference = 1 << 2, Read = 1 << 3, Write = 1 << 4, Call = 1 << 5, Dynamic = 1 << 6, Address = 1 << 7, Implicit = 1 << 8, All = (1 << 9) - 1, }; REFLECT_UNDERLYING_B(Role); inline uint16_t operator&(Role lhs, Role rhs) { return uint16_t(lhs) & uint16_t(rhs); } inline Role operator|(Role lhs, Role rhs) { return Role(uint16_t(lhs) | uint16_t(rhs)); } struct SymbolIdx { Usr usr; Kind kind; bool operator==(const SymbolIdx &o) const { return usr == o.usr && kind == o.kind; } bool operator<(const SymbolIdx &o) const { return usr != o.usr ? usr < o.usr : kind < o.kind; } }; // |id,kind| refer to the referenced entity. struct SymbolRef { Range range; Usr usr; Kind kind; Role role; operator SymbolIdx() const { return {usr, kind}; } std::tuple ToTuple() const { return std::make_tuple(range, usr, kind, role); } bool operator==(const SymbolRef &o) const { return ToTuple() == o.ToTuple(); } bool Valid() const { return range.Valid(); } }; struct ExtentRef : SymbolRef { Range extent; std::tuple ToTuple() const { return std::make_tuple(range, usr, kind, role, extent); } bool operator==(const ExtentRef &o) const { return ToTuple() == o.ToTuple(); } }; struct Ref { Range range; Role role; bool Valid() const { return range.Valid(); } std::tuple ToTuple() const { return std::make_tuple(range, role); } bool operator==(const Ref &o) const { return ToTuple() == o.ToTuple(); } bool operator<(const Ref &o) const { return ToTuple() < o.ToTuple(); } }; // Represents an occurrence of a variable/type, |usr,kind| refer to the lexical // parent. struct Use : Ref { // |file| is used in Query* but not in Index* int file_id = -1; bool operator==(const Use &o) const { // lexical container info is ignored. return range == o.range && file_id == o.file_id; } }; struct DeclRef : Use { Range extent; }; void Reflect(JsonReader &visitor, SymbolRef &value); void Reflect(JsonReader &visitor, Use &value); void Reflect(JsonReader &visitor, DeclRef &value); void Reflect(JsonWriter &visitor, SymbolRef &value); void Reflect(JsonWriter &visitor, Use &value); void Reflect(JsonWriter &visitor, DeclRef &value); void Reflect(BinaryReader &visitor, SymbolRef &value); void Reflect(BinaryReader &visitor, Use &value); void Reflect(BinaryReader &visitor, DeclRef &value); void Reflect(BinaryWriter &visitor, SymbolRef &value); void Reflect(BinaryWriter &visitor, Use &value); void Reflect(BinaryWriter &visitor, DeclRef &value); template using VectorAdapter = std::vector>; template struct NameMixin { std::string_view Name(bool qualified) const { auto self = static_cast(this); return qualified ? std::string_view(self->detailed_name + self->qual_name_offset, self->short_name_offset - self->qual_name_offset + self->short_name_size) : std::string_view(self->detailed_name + self->short_name_offset, self->short_name_size); } }; template