// Copyright 2017-2018 ccls Authors // SPDX-License-Identifier: Apache-2.0 #pragma once #include "indexer.h" #include "serializer.h" #include #include #include namespace llvm { template <> struct DenseMapInfo { static inline SymbolRef getEmptyKey() { return {}; } static inline SymbolRef getTombstoneKey() { SymbolRef ret{}; ret.usr = -1; return ret; } static unsigned getHashValue(SymbolRef sym) { return std::hash()(sym); } static bool isEqual(SymbolRef l, SymbolRef r) { return l == r; } }; } struct QueryFile { struct Def { std::string path; std::vector args; LanguageId language; // Includes in the file. std::vector includes; // Parts of the file which are disabled. std::vector skipped_ranges; // Used by |$ccls/freshenIndex|. std::vector dependencies; }; using DefUpdate = std::pair; int id = -1; std::optional def; llvm::DenseMap symbol2refcnt; llvm::DenseMap outline2refcnt; }; template struct QueryEntity { using Def = QDef; Def *AnyDef() { Def *ret = nullptr; for (auto &i : static_cast(this)->def) { ret = &i; if (i.spell) break; } return ret; } const Def *AnyDef() const { return const_cast(this)->AnyDef(); } }; using UseUpdate = std::unordered_map, std::vector>>; using UsrUpdate = std::unordered_map, std::vector>>; struct QueryFunc : QueryEntity { Usr usr; llvm::SmallVector def; std::vector declarations; std::vector uses; std::vector derived; }; struct QueryType : QueryEntity { Usr usr; llvm::SmallVector def; std::vector declarations; std::vector uses; std::vector derived; std::vector instances; }; struct QueryVar : QueryEntity { Usr usr; llvm::SmallVector def; std::vector declarations; std::vector uses; }; struct IndexUpdate { // Creates a new IndexUpdate based on the delta from previous to current. If // no delta computation should be done just pass null for previous. static IndexUpdate CreateDelta(IndexFile *previous, IndexFile *current); int file_id; // Dummy one to refresh all semantic highlight. bool refresh = false; decltype(IndexFile::lid2path) prev_lid2path; decltype(IndexFile::lid2path) lid2path; // File updates. std::optional files_removed; std::optional files_def_update; // Function updates. int funcs_hint; std::vector> funcs_removed; std::vector> funcs_def_update; UseUpdate funcs_declarations; UseUpdate funcs_uses; UsrUpdate funcs_derived; // Type updates. int types_hint; std::vector> types_removed; std::vector> types_def_update; UseUpdate types_declarations; UseUpdate types_uses; UsrUpdate types_derived; UsrUpdate types_instances; // Variable updates. int vars_hint; std::vector> vars_removed; std::vector> vars_def_update; UseUpdate vars_declarations; UseUpdate vars_uses; }; struct WrappedUsr { Usr usr; }; template <> struct llvm::DenseMapInfo { static inline WrappedUsr getEmptyKey() { return {0}; } static inline WrappedUsr getTombstoneKey() { return {~0ULL}; } static unsigned getHashValue(WrappedUsr w) { return w.usr; } static bool isEqual(WrappedUsr l, WrappedUsr r) { return l.usr == r.usr; } }; using Lid2file_id = std::unordered_map; // The query database is heavily optimized for fast queries. It is stored // in-memory. struct DB { std::vector files; llvm::StringMap name2file_id; llvm::DenseMap func_usr, type_usr, var_usr; std::vector funcs; std::vector types; std::vector vars; template void RemoveUsrs(SymbolKind kind, int file_id, const std::vector> &to_remove); // Insert the contents of |update| into |db|. void ApplyIndexUpdate(IndexUpdate *update); int GetFileId(const std::string &path); int Update(QueryFile::DefUpdate &&u); void Update(const Lid2file_id &, int file_id, std::vector> &&us); void Update(const Lid2file_id &, int file_id, std::vector> &&us); void Update(const Lid2file_id &, int file_id, std::vector> &&us); std::string_view GetSymbolName(SymbolIdx sym, bool qualified); bool HasFunc(Usr usr) const { return func_usr.count({usr}); } bool HasType(Usr usr) const { return type_usr.count({usr}); } bool HasVar(Usr usr) const { return var_usr.count({usr}); } QueryFunc &Func(Usr usr) { return funcs[func_usr[{usr}]]; } QueryType &Type(Usr usr) { return types[type_usr[{usr}]]; } QueryVar &Var(Usr usr) { return vars[var_usr[{usr}]]; } QueryFile &GetFile(SymbolIdx ref) { return files[ref.usr]; } QueryFunc &GetFunc(SymbolIdx ref) { return Func(ref.usr); } QueryType &GetType(SymbolIdx ref) { return Type(ref.usr); } QueryVar &GetVar(SymbolIdx ref) { return Var(ref.usr); } };