/* Copyright 2017-2018 ccls Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ #pragma once #include "indexer.h" #include "serializer.h" #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 DeclRefUpdate = std::unordered_map, std::vector>>; 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; DeclRefUpdate funcs_declarations; UseUpdate funcs_uses; UsrUpdate funcs_derived; // Type updates. int types_hint; std::vector> types_removed; std::vector> types_def_update; DeclRefUpdate 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; DeclRefUpdate 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); } };