//===--- SymbolID.h ----------------------------------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLID_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLID_H #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include namespace clang { namespace clangd { // The class identifies a particular C++ symbol (class, function, method, etc). // // As USRs (Unified Symbol Resolution) could be large, especially for functions // with long type arguments, SymbolID is using truncated SHA1(USR) values to // guarantee the uniqueness of symbols while using a relatively small amount of // memory (vs storing USRs directly). // // SymbolID can be used as key in the symbol indexes to lookup the symbol. class SymbolID { public: SymbolID() = default; explicit SymbolID(llvm::StringRef USR); bool operator==(const SymbolID &Sym) const { return HashValue == Sym.HashValue; } bool operator!=(const SymbolID &Sym) const { return !(*this == Sym); } bool operator<(const SymbolID &Sym) const { // Avoid lexicographic compare which requires swapping bytes or even memcmp! return llvm::bit_cast(HashValue) < llvm::bit_cast(Sym.HashValue); } // The stored hash is truncated to RawSize bytes. // This trades off memory against the number of symbols we can handle. constexpr static size_t RawSize = 8; llvm::StringRef raw() const; static SymbolID fromRaw(llvm::StringRef); // Returns a hex encoded string. std::string str() const; static llvm::Expected fromStr(llvm::StringRef); bool isNull() const { return *this == SymbolID(); } explicit operator bool() const { return !isNull(); } private: using IntTy = uint64_t; static_assert(sizeof(IntTy) == RawSize); std::array HashValue{}; }; inline llvm::hash_code hash_value(const SymbolID &ID) { // We already have a good hash, just return the first bytes. static_assert(sizeof(size_t) <= SymbolID::RawSize, "size_t longer than SHA1!"); size_t Result; memcpy(&Result, ID.raw().data(), sizeof(size_t)); return llvm::hash_code(Result); } // Write SymbolID into the given stream. SymbolID is encoded as ID.str(). llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolID &ID); } // namespace clangd } // namespace clang namespace llvm { // Support SymbolIDs as DenseMap keys. template <> struct DenseMapInfo { static inline clang::clangd::SymbolID getEmptyKey() { static clang::clangd::SymbolID EmptyKey("EMPTYKEY"); return EmptyKey; } static inline clang::clangd::SymbolID getTombstoneKey() { static clang::clangd::SymbolID TombstoneKey("TOMBSTONEKEY"); return TombstoneKey; } static unsigned getHashValue(const clang::clangd::SymbolID &Sym) { return hash_value(Sym); } static bool isEqual(const clang::clangd::SymbolID &LHS, const clang::clangd::SymbolID &RHS) { return LHS == RHS; } }; } // namespace llvm #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLID_H