1 #include "query.h"
2 
3 #include "indexer.h"
4 #include "serializer.h"
5 #include "serializers/json.h"
6 
7 #include <doctest/doctest.h>
8 #include <optional.h>
9 #include <loguru.hpp>
10 
11 #include <cassert>
12 #include <cstdint>
13 #include <functional>
14 #include <string>
15 #include <unordered_map>
16 #include <unordered_set>
17 
18 // TODO: Make all copy constructors explicit.
19 
20 namespace {
21 
22 template <typename T>
VerifyUnique(const std::vector<T> & values0)23 void VerifyUnique(const std::vector<T>& values0) {
24 // FIXME: Run on a big code-base for a while and verify no assertions are
25 // triggered.
26 #if false
27   auto values = values0;
28   std::sort(values.begin(), values.end());
29   assert(std::unique(values.begin(), values.end()) == values.end());
30 #endif
31 }
32 
33 template <typename T>
RemoveRange(std::vector<T> * dest,const std::vector<T> & to_remove)34 void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
35   std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
36   dest->erase(
37       std::remove_if(dest->begin(), dest->end(),
38                      [&](const T& t) { return to_remove_set.count(t) > 0; }),
39       dest->end());
40 }
41 
ToQuery(const IdMap & id_map,const IndexType::Def & type)42 optional<QueryType::Def> ToQuery(const IdMap& id_map,
43                                  const IndexType::Def& type) {
44   if (type.detailed_name.empty())
45     return nullopt;
46 
47   QueryType::Def result;
48   result.detailed_name = type.detailed_name;
49   result.short_name_offset = type.short_name_offset;
50   result.short_name_size = type.short_name_size;
51   result.kind = type.kind;
52   if (!type.hover.empty())
53     result.hover = type.hover;
54   if (!type.comments.empty())
55     result.comments = type.comments;
56   result.file = id_map.primary_file;
57   result.spell = id_map.ToQuery(type.spell);
58   result.extent = id_map.ToQuery(type.extent);
59   result.alias_of = id_map.ToQuery(type.alias_of);
60   result.bases = id_map.ToQuery(type.bases);
61   result.types = id_map.ToQuery(type.types);
62   result.funcs = id_map.ToQuery(type.funcs);
63   result.vars = id_map.ToQuery(type.vars);
64   return result;
65 }
66 
ToQuery(const IdMap & id_map,const IndexFunc::Def & func)67 optional<QueryFunc::Def> ToQuery(const IdMap& id_map,
68                                  const IndexFunc::Def& func) {
69   if (func.detailed_name.empty())
70     return nullopt;
71 
72   QueryFunc::Def result;
73   result.detailed_name = func.detailed_name;
74   result.short_name_offset = func.short_name_offset;
75   result.short_name_size = func.short_name_size;
76   result.kind = func.kind;
77   result.storage = func.storage;
78   if (!func.hover.empty())
79     result.hover = func.hover;
80   if (!func.comments.empty())
81     result.comments = func.comments;
82   result.file = id_map.primary_file;
83   result.spell = id_map.ToQuery(func.spell);
84   result.extent = id_map.ToQuery(func.extent);
85   result.declaring_type = id_map.ToQuery(func.declaring_type);
86   result.bases = id_map.ToQuery(func.bases);
87   result.vars = id_map.ToQuery(func.vars);
88   result.callees = id_map.ToQuery(func.callees);
89   return result;
90 }
91 
ToQuery(const IdMap & id_map,const IndexVar::Def & var)92 optional<QueryVar::Def> ToQuery(const IdMap& id_map, const IndexVar::Def& var) {
93   if (var.detailed_name.empty())
94     return nullopt;
95 
96   QueryVar::Def result;
97   result.detailed_name = var.detailed_name;
98   result.short_name_offset = var.short_name_offset;
99   result.short_name_size = var.short_name_size;
100   if (!var.hover.empty())
101     result.hover = var.hover;
102   if (!var.comments.empty())
103     result.comments = var.comments;
104   result.file = id_map.primary_file;
105   result.spell = id_map.ToQuery(var.spell);
106   result.extent = id_map.ToQuery(var.extent);
107   result.type = id_map.ToQuery(var.type);
108   result.kind = var.kind;
109   result.storage = var.storage;
110   return result;
111 }
112 
113 // Adds the mergeable updates in |source| to |dest|. If a mergeable update for
114 // the destination type already exists, it will be combined. This makes merging
115 // updates take longer but reduces import time on the querydb thread.
116 template <typename TId, typename TValue>
AddMergeableRange(std::vector<MergeableUpdate<TId,TValue>> * dest,std::vector<MergeableUpdate<TId,TValue>> && source)117 void AddMergeableRange(std::vector<MergeableUpdate<TId, TValue>>* dest,
118                        std::vector<MergeableUpdate<TId, TValue>>&& source) {
119   // TODO: Consider caching the lookup table. It can probably save even more
120   // time at the cost of some additional memory.
121 
122   // Build lookup table.
123   spp::sparse_hash_map<TId, size_t> id_to_index;
124   id_to_index.resize(dest->size());
125   for (size_t i = 0; i < dest->size(); ++i)
126     id_to_index[(*dest)[i].id] = i;
127 
128   // Add entries. Try to add them to an existing entry.
129   for (auto& entry : source) {
130     auto it = id_to_index.find(entry.id);
131     if (it != id_to_index.end()) {
132       AddRange(&(*dest)[it->second].to_add, std::move(entry.to_add));
133       AddRange(&(*dest)[it->second].to_remove, std::move(entry.to_remove));
134     } else {
135       dest->push_back(std::move(entry));
136     }
137   }
138 }
139 
140 // Compares |previous| and |current|, adding all elements that are in |previous|
141 // but not |current| to |removed|, and all elements that are in |current| but
142 // not |previous| to |added|.
143 //
144 // Returns true iff |removed| or |added| are non-empty.
145 template <typename T>
ComputeDifferenceForUpdate(std::vector<T> && previous,std::vector<T> && current,std::vector<T> * removed,std::vector<T> * added)146 bool ComputeDifferenceForUpdate(std::vector<T>&& previous,
147                                 std::vector<T>&& current,
148                                 std::vector<T>* removed,
149                                 std::vector<T>* added) {
150   // We need to sort to use std::set_difference.
151   std::sort(previous.begin(), previous.end());
152   std::sort(current.begin(), current.end());
153 
154   auto it0 = previous.begin(), it1 = current.begin();
155   while (it0 != previous.end() && it1 != current.end()) {
156     // Elements in |previous| that are not in |current|.
157     if (*it0 < *it1)
158       removed->push_back(std::move(*it0++));
159     // Elements in |current| that are not in |previous|.
160     else if (*it1 < *it0)
161       added->push_back(std::move(*it1++));
162     else
163       ++it0, ++it1;
164   }
165   while (it0 != previous.end())
166     removed->push_back(std::move(*it0++));
167   while (it1 != current.end())
168     added->push_back(std::move(*it1++));
169 
170   return !removed->empty() || !added->empty();
171 }
172 
173 template <typename T>
CompareGroups(std::vector<T> & previous_data,std::vector<T> & current_data,std::function<void (T *)> on_removed,std::function<void (T *)> on_added,std::function<void (T *,T *)> on_found)174 void CompareGroups(std::vector<T>& previous_data,
175                    std::vector<T>& current_data,
176                    std::function<void(T*)> on_removed,
177                    std::function<void(T*)> on_added,
178                    std::function<void(T*, T*)> on_found) {
179   std::sort(previous_data.begin(), previous_data.end());
180   std::sort(current_data.begin(), current_data.end());
181 
182   auto prev_it = previous_data.begin();
183   auto curr_it = current_data.begin();
184   while (prev_it != previous_data.end() && curr_it != current_data.end()) {
185     // same id
186     if (prev_it->usr == curr_it->usr) {
187       on_found(&*prev_it, &*curr_it);
188       ++prev_it;
189       ++curr_it;
190     }
191 
192     // prev_id is smaller - prev_it has data curr_it does not have.
193     else if (prev_it->usr < curr_it->usr) {
194       on_removed(&*prev_it);
195       ++prev_it;
196     }
197 
198     // prev_id is bigger - curr_it has data prev_it does not have.
199     else {
200       on_added(&*curr_it);
201       ++curr_it;
202     }
203   }
204 
205   // if prev_it still has data, that means it is not in curr_it and was removed.
206   while (prev_it != previous_data.end()) {
207     on_removed(&*prev_it);
208     ++prev_it;
209   }
210 
211   // if curr_it still has data, that means it is not in prev_it and was added.
212   while (curr_it != current_data.end()) {
213     on_added(&*curr_it);
214     ++curr_it;
215   }
216 }
217 
BuildFileDefUpdate(const IdMap & id_map,const IndexFile & indexed)218 QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map,
219                                         const IndexFile& indexed) {
220   QueryFile::Def def;
221   def.file = id_map.primary_file;
222   def.path = indexed.path;
223   def.args = indexed.args;
224   def.includes = indexed.includes;
225   def.inactive_regions = indexed.skipped_by_preprocessor;
226   def.dependencies = indexed.dependencies;
227 
228   // Convert enum to markdown compatible strings
229   def.language = [&indexed]() {
230     switch (indexed.language) {
231       case LanguageId::C:
232         return "c";
233       case LanguageId::Cpp:
234         return "cpp";
235       case LanguageId::ObjC:
236         return "objective-c";
237       case LanguageId::ObjCpp:
238         return "objective-cpp";
239       default:
240         return "";
241     }
242   }();
243 
244   auto add_all_symbols = [&](Reference ref, AnyId id, SymbolKind kind) {
245     def.all_symbols.push_back(
246         QueryId::SymbolRef(ref.range, id, kind, ref.role));
247   };
248   auto add_outline = [&](Reference ref, AnyId id, SymbolKind kind) {
249     def.outline.push_back(QueryId::SymbolRef(ref.range, id, kind, ref.role));
250   };
251 
252   for (const IndexType& type : indexed.types) {
253     QueryId::Type id = id_map.ToQuery(type.id);
254     if (type.def.spell)
255       add_all_symbols(*type.def.spell, id, SymbolKind::Type);
256     if (type.def.extent)
257       add_outline(*type.def.extent, id, SymbolKind::Type);
258     for (auto decl : type.declarations) {
259       add_all_symbols(decl, id, SymbolKind::Type);
260       // Constructor positions have references to the class,
261       // which we do not want to show in textDocument/documentSymbol
262       if (!(decl.role & Role::Reference))
263         add_outline(decl, id, SymbolKind::Type);
264     }
265     for (Reference use : type.uses)
266       add_all_symbols(use, id, SymbolKind::Type);
267   }
268   for (const IndexFunc& func : indexed.funcs) {
269     QueryId::Func id = id_map.ToQuery(func.id);
270     if (func.def.spell)
271       add_all_symbols(*func.def.spell, id, SymbolKind::Func);
272     if (func.def.extent)
273       add_outline(*func.def.extent, id, SymbolKind::Func);
274     for (const IndexFunc::Declaration& decl : func.declarations) {
275       add_all_symbols(decl.spell, id, SymbolKind::Func);
276       add_outline(decl.spell, id, SymbolKind::Func);
277     }
278     for (auto use : func.uses) {
279       // Make ranges of implicit function calls larger (spanning one more column
280       // to the left/right). This is hacky but useful. e.g.
281       // textDocument/definition on the space/semicolon in `A a;` or `return
282       // 42;` will take you to the constructor.
283       if (use.role & Role::Implicit) {
284         if (use.range.start.column > 0)
285           use.range.start.column--;
286         use.range.end.column++;
287       }
288       add_all_symbols(use, id, SymbolKind::Func);
289     }
290   }
291   for (const IndexVar& var : indexed.vars) {
292     QueryId::Var id = id_map.ToQuery(var.id);
293     if (var.def.spell)
294       add_all_symbols(*var.def.spell, id, SymbolKind::Var);
295     if (var.def.extent)
296       add_outline(*var.def.extent, id, SymbolKind::Var);
297     for (auto decl : var.declarations) {
298       add_all_symbols(decl, id, SymbolKind::Var);
299       add_outline(decl, id, SymbolKind::Var);
300     }
301     for (auto use : var.uses)
302       add_all_symbols(use, id, SymbolKind::Var);
303   }
304 
305   std::sort(def.outline.begin(), def.outline.end(),
306             [](const QueryId::SymbolRef& a, const QueryId::SymbolRef& b) {
307               return a.range.start < b.range.start;
308             });
309   std::sort(def.all_symbols.begin(), def.all_symbols.end(),
310             [](const QueryId::SymbolRef& a, const QueryId::SymbolRef& b) {
311               return a.range.start < b.range.start;
312             });
313 
314   return QueryFile::DefUpdate(def, indexed.file_contents);
315 }
316 
GetQueryFileIdFromPath(QueryDatabase * query_db,const AbsolutePath & path,bool create_if_missing)317 Maybe<QueryId::File> GetQueryFileIdFromPath(QueryDatabase* query_db,
318                                             const AbsolutePath& path,
319                                             bool create_if_missing) {
320   auto it = query_db->usr_to_file.find(path);
321   if (it != query_db->usr_to_file.end())
322     return QueryId::File(it->second.id);
323   if (!create_if_missing)
324     return {};
325 
326   RawId idx = query_db->files.size();
327   query_db->usr_to_file[path] = QueryId::File(idx);
328   query_db->files.push_back(QueryFile(path));
329   return QueryId::File(idx);
330 }
331 
GetQueryTypeIdFromUsr(QueryDatabase * query_db,Usr usr,bool create_if_missing)332 Maybe<QueryId::Type> GetQueryTypeIdFromUsr(QueryDatabase* query_db,
333                                            Usr usr,
334                                            bool create_if_missing) {
335   auto it = query_db->usr_to_type.find(usr);
336   if (it != query_db->usr_to_type.end())
337     return QueryId::Type(it->second.id);
338   if (!create_if_missing)
339     return {};
340 
341   RawId idx = query_db->types.size();
342   query_db->usr_to_type[usr] = QueryId::Type(idx);
343   query_db->types.push_back(QueryType(usr));
344   return QueryId::Type(idx);
345 }
346 
GetQueryFuncIdFromUsr(QueryDatabase * query_db,Usr usr,bool create_if_missing)347 Maybe<QueryId::Func> GetQueryFuncIdFromUsr(QueryDatabase* query_db,
348                                            Usr usr,
349                                            bool create_if_missing) {
350   auto it = query_db->usr_to_func.find(usr);
351   if (it != query_db->usr_to_func.end())
352     return QueryId::Func(it->second.id);
353   if (!create_if_missing)
354     return {};
355 
356   RawId idx = query_db->funcs.size();
357   query_db->usr_to_func[usr] = QueryId::Func(idx);
358   query_db->funcs.push_back(QueryFunc(usr));
359   return QueryId::Func(idx);
360 }
361 
GetQueryVarIdFromUsr(QueryDatabase * query_db,Usr usr,bool create_if_missing)362 Maybe<QueryId::Var> GetQueryVarIdFromUsr(QueryDatabase* query_db,
363                                          Usr usr,
364                                          bool create_if_missing) {
365   auto it = query_db->usr_to_var.find(usr);
366   if (it != query_db->usr_to_var.end())
367     return QueryId::Var(it->second.id);
368   if (!create_if_missing)
369     return {};
370 
371   RawId idx = query_db->vars.size();
372   query_db->usr_to_var[usr] = QueryId::Var(idx);
373   query_db->vars.push_back(QueryVar(usr));
374   return QueryId::Var(idx);
375 }
376 
377 // Returns true if an element with the same file is found.
378 template <typename Q>
TryReplaceDef(std::forward_list<Q> & def_list,Q && def)379 bool TryReplaceDef(std::forward_list<Q>& def_list, Q&& def) {
380   for (auto& def1 : def_list)
381     if (def1.file == def.file) {
382       if (!def1.spell || def.spell)
383         def1 = std::move(def);
384       return true;
385     }
386   return false;
387 }
388 
389 }  // namespace
390 
GetQueryFileIdFromPath(const std::string & path)391 Maybe<QueryId::File> QueryDatabase::GetQueryFileIdFromPath(
392     const std::string& path) {
393   return ::GetQueryFileIdFromPath(this, path, false);
394 }
395 
GetQueryTypeIdFromUsr(Usr usr)396 Maybe<QueryId::Type> QueryDatabase::GetQueryTypeIdFromUsr(Usr usr) {
397   return ::GetQueryTypeIdFromUsr(this, usr, false);
398 }
399 
GetQueryFuncIdFromUsr(Usr usr)400 Maybe<QueryId::Func> QueryDatabase::GetQueryFuncIdFromUsr(Usr usr) {
401   return ::GetQueryFuncIdFromUsr(this, usr, false);
402 }
403 
GetQueryVarIdFromUsr(Usr usr)404 Maybe<QueryId::Var> QueryDatabase::GetQueryVarIdFromUsr(Usr usr) {
405   return ::GetQueryVarIdFromUsr(this, usr, false);
406 }
407 
IdMap(QueryDatabase * query_db,const IdCache & local_ids)408 IdMap::IdMap(QueryDatabase* query_db, const IdCache& local_ids)
409     : local_ids(local_ids) {
410   // LOG_S(INFO) << "Creating IdMap for " << local_ids.primary_file;
411   primary_file =
412       *GetQueryFileIdFromPath(query_db, local_ids.primary_file, true);
413 
414   cached_type_ids_.resize(local_ids.type_id_to_usr.size());
415   for (const auto& entry : local_ids.type_id_to_usr)
416     cached_type_ids_[entry.first] =
417         *GetQueryTypeIdFromUsr(query_db, entry.second, true);
418 
419   cached_func_ids_.resize(local_ids.func_id_to_usr.size());
420   for (const auto& entry : local_ids.func_id_to_usr)
421     cached_func_ids_[entry.first] =
422         *GetQueryFuncIdFromUsr(query_db, entry.second, true);
423 
424   cached_var_ids_.resize(local_ids.var_id_to_usr.size());
425   for (const auto& entry : local_ids.var_id_to_usr)
426     cached_var_ids_[entry.first] =
427         *GetQueryVarIdFromUsr(query_db, entry.second, true);
428 }
429 
ToQuery(SymbolKind kind,Id<void> id) const430 Id<void> IdMap::ToQuery(SymbolKind kind, Id<void> id) const {
431   switch (kind) {
432     case SymbolKind::File:
433       return primary_file;
434     case SymbolKind::Type:
435       return ToQuery(IndexId::Type(id.id));
436     case SymbolKind::Func:
437       return ToQuery(IndexId::Func(id.id));
438     case SymbolKind::Var:
439       return ToQuery(IndexId::Var(id.id));
440     case SymbolKind::Invalid:
441       break;
442   }
443   assert(false);
444   return Id<void>(-1);
445 }
446 
ToQuery(IndexId::Type id) const447 QueryId::Type IdMap::ToQuery(IndexId::Type id) const {
448   assert(cached_type_ids_.find(id) != cached_type_ids_.end());
449   return QueryId::Type(cached_type_ids_.find(id)->second);
450 }
ToQuery(IndexId::Func id) const451 QueryId::Func IdMap::ToQuery(IndexId::Func id) const {
452   assert(cached_func_ids_.find(id) != cached_func_ids_.end());
453   return QueryId::Func(cached_func_ids_.find(id)->second);
454 }
ToQuery(IndexId::Var id) const455 QueryId::Var IdMap::ToQuery(IndexId::Var id) const {
456   assert(cached_var_ids_.find(id) != cached_var_ids_.end());
457   return QueryId::Var(cached_var_ids_.find(id)->second);
458 }
459 
ToQuery(IndexId::SymbolRef ref) const460 QueryId::SymbolRef IdMap::ToQuery(IndexId::SymbolRef ref) const {
461   QueryId::SymbolRef result;
462   result.range = ref.range;
463   result.id = ToQuery(ref.kind, ref.id);
464   result.kind = ref.kind;
465   result.role = ref.role;
466   return result;
467 }
ToQuery(IndexId::LexicalRef ref) const468 QueryId::LexicalRef IdMap::ToQuery(IndexId::LexicalRef ref) const {
469   QueryId::LexicalRef result;
470   result.file = primary_file;
471   result.range = ref.range;
472   result.id = ToQuery(ref.kind, ref.id);
473   result.kind = ref.kind;
474   result.role = ref.role;
475   return result;
476 }
ToQuery(IndexFunc::Declaration decl) const477 QueryId::LexicalRef IdMap::ToQuery(IndexFunc::Declaration decl) const {
478   return ToQuery(decl.spell);
479 }
480 
481 // ----------------------
482 // INDEX THREAD FUNCTIONS
483 // ----------------------
484 
485 // static
CreateDelta(const IdMap * previous_id_map,const IdMap * current_id_map,IndexFile * previous,IndexFile * current)486 IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map,
487                                      const IdMap* current_id_map,
488                                      IndexFile* previous,
489                                      IndexFile* current) {
490   // This function runs on an indexer thread.
491 
492   if (!previous_id_map) {
493     assert(!previous);
494     IndexFile empty(current->path, "<empty>");
495     return IndexUpdate(*current_id_map, *current_id_map, empty, *current);
496   }
497   return IndexUpdate(*previous_id_map, *current_id_map, *previous, *current);
498 }
499 
IndexUpdate(const IdMap & previous_id_map,const IdMap & current_id_map,IndexFile & previous_file,IndexFile & current_file)500 IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
501                          const IdMap& current_id_map,
502                          IndexFile& previous_file,
503                          IndexFile& current_file) {
504 // This function runs on an indexer thread.
505 
506 // |query_name| is the name of the variable on the query type.
507 // |index_name| is the name of the variable on the index type.
508 // |type| is the type of the variable.
509 #define PROCESS_UPDATE_DIFF(type_id, query_name, index_name, type)       \
510   {                                                                      \
511     /* Check for changes. */                                             \
512     std::vector<type> removed, added;                                    \
513     auto query_previous = previous_id_map.ToQuery(previous->index_name); \
514     auto query_current = current_id_map.ToQuery(current->index_name);    \
515     bool did_add = ComputeDifferenceForUpdate(std::move(query_previous), \
516                                               std::move(query_current),  \
517                                               &removed, &added);         \
518     if (did_add) {                                                       \
519       query_name.push_back(MergeableUpdate<type_id, type>(               \
520           current_id_map.ToQuery(current->id), std::move(added),         \
521           std::move(removed)));                                          \
522     }                                                                    \
523   }
524   // File
525   files_def_update.push_back(BuildFileDefUpdate(current_id_map, current_file));
526 
527   // **NOTE** We only remove entries if they were defined in the previous index.
528   // For example, if a type is included from another file it will be defined
529   // simply so we can attribute the usage/reference to it. If the reference goes
530   // away we don't want to remove the type/func/var usage.
531 
532   // Types
533   CompareGroups<IndexType>(
534       previous_file.types, current_file.types,
535       /*onRemoved:*/
536       [this, &previous_id_map](IndexType* type) {
537         if (type->def.spell)
538           types_removed.push_back(type->usr);
539         if (!type->declarations.empty())
540           types_declarations.push_back(QueryType::DeclarationsUpdate(
541               previous_id_map.ToQuery(type->id), {},
542               previous_id_map.ToQuery(type->declarations)));
543         if (!type->derived.empty())
544           types_derived.push_back(
545               QueryType::DerivedUpdate(previous_id_map.ToQuery(type->id), {},
546                                        previous_id_map.ToQuery(type->derived)));
547         if (!type->instances.empty())
548           types_instances.push_back(QueryType::InstancesUpdate(
549               previous_id_map.ToQuery(type->id), {},
550               previous_id_map.ToQuery(type->instances)));
551         if (!type->uses.empty())
552           types_uses.push_back(
553               QueryType::UsesUpdate(previous_id_map.ToQuery(type->id), {},
554                                     previous_id_map.ToQuery(type->uses)));
555       },
556       /*onAdded:*/
557       [this, &current_id_map](IndexType* type) {
558         optional<QueryType::Def> def_update =
559             ToQuery(current_id_map, type->def);
560         if (def_update)
561           types_def_update.push_back(
562               QueryType::DefUpdate(type->usr, std::move(*def_update)));
563         if (!type->declarations.empty())
564           types_declarations.push_back(QueryType::DeclarationsUpdate(
565               current_id_map.ToQuery(type->id),
566               current_id_map.ToQuery(type->declarations)));
567         if (!type->derived.empty())
568           types_derived.push_back(
569               QueryType::DerivedUpdate(current_id_map.ToQuery(type->id),
570                                        current_id_map.ToQuery(type->derived)));
571         if (!type->instances.empty())
572           types_instances.push_back(QueryType::InstancesUpdate(
573               current_id_map.ToQuery(type->id),
574               current_id_map.ToQuery(type->instances)));
575         if (!type->uses.empty())
576           types_uses.push_back(
577               QueryType::UsesUpdate(current_id_map.ToQuery(type->id),
578                                     current_id_map.ToQuery(type->uses)));
579       },
580       /*onFound:*/
581       [this, &previous_id_map, &current_id_map](IndexType* previous,
582                                                 IndexType* current) {
583         optional<QueryType::Def> previous_remapped_def =
584             ToQuery(previous_id_map, previous->def);
585         optional<QueryType::Def> current_remapped_def =
586             ToQuery(current_id_map, current->def);
587         if (current_remapped_def &&
588             previous_remapped_def != current_remapped_def &&
589             !current_remapped_def->detailed_name.empty()) {
590           types_def_update.push_back(QueryType::DefUpdate(
591               current->usr, std::move(*current_remapped_def)));
592         }
593 
594         PROCESS_UPDATE_DIFF(QueryId::Type, types_declarations, declarations,
595                             QueryId::LexicalRef);
596         PROCESS_UPDATE_DIFF(QueryId::Type, types_derived, derived,
597                             QueryId::Type);
598         PROCESS_UPDATE_DIFF(QueryId::Type, types_instances, instances,
599                             QueryId::Var);
600         PROCESS_UPDATE_DIFF(QueryId::Type, types_uses, uses,
601                             QueryId::LexicalRef);
602       });
603 
604   // Functions
605   CompareGroups<IndexFunc>(
606       previous_file.funcs, current_file.funcs,
607       /*onRemoved:*/
608       [this, &previous_id_map](IndexFunc* func) {
609         if (func->def.spell)
610           funcs_removed.emplace_back(func->usr, previous_id_map.primary_file);
611         if (!func->declarations.empty())
612           funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(
613               previous_id_map.ToQuery(func->id), {},
614               previous_id_map.ToQuery(func->declarations)));
615         if (!func->derived.empty())
616           funcs_derived.push_back(
617               QueryFunc::DerivedUpdate(previous_id_map.ToQuery(func->id), {},
618                                        previous_id_map.ToQuery(func->derived)));
619         if (!func->uses.empty())
620           funcs_uses.push_back(
621               QueryFunc::UsesUpdate(previous_id_map.ToQuery(func->id), {},
622                                     previous_id_map.ToQuery(func->uses)));
623       },
624       /*onAdded:*/
625       [this, &current_id_map](IndexFunc* func) {
626         optional<QueryFunc::Def> def_update =
627             ToQuery(current_id_map, func->def);
628         if (def_update)
629           funcs_def_update.push_back(
630               QueryFunc::DefUpdate(func->usr, std::move(*def_update)));
631         if (!func->declarations.empty())
632           funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(
633               current_id_map.ToQuery(func->id),
634               current_id_map.ToQuery(func->declarations)));
635         if (!func->derived.empty())
636           funcs_derived.push_back(
637               QueryFunc::DerivedUpdate(current_id_map.ToQuery(func->id),
638                                        current_id_map.ToQuery(func->derived)));
639         if (!func->uses.empty())
640           funcs_uses.push_back(
641               QueryFunc::UsesUpdate(current_id_map.ToQuery(func->id),
642                                     current_id_map.ToQuery(func->uses)));
643       },
644       /*onFound:*/
645       [this, &previous_id_map, &current_id_map](IndexFunc* previous,
646                                                 IndexFunc* current) {
647         optional<QueryFunc::Def> previous_remapped_def =
648             ToQuery(previous_id_map, previous->def);
649         optional<QueryFunc::Def> current_remapped_def =
650             ToQuery(current_id_map, current->def);
651         if (current_remapped_def &&
652             previous_remapped_def != current_remapped_def &&
653             !current_remapped_def->detailed_name.empty()) {
654           funcs_def_update.push_back(QueryFunc::DefUpdate(
655               current->usr, std::move(*current_remapped_def)));
656         }
657 
658         PROCESS_UPDATE_DIFF(QueryId::Func, funcs_declarations, declarations,
659                             QueryId::LexicalRef);
660         PROCESS_UPDATE_DIFF(QueryId::Func, funcs_derived, derived,
661                             QueryId::Func);
662         PROCESS_UPDATE_DIFF(QueryId::Func, funcs_uses, uses,
663                             QueryId::LexicalRef);
664       });
665 
666   // Variables
667   CompareGroups<IndexVar>(
668       previous_file.vars, current_file.vars,
669       /*onRemoved:*/
670       [this, &previous_id_map](IndexVar* var) {
671         if (var->def.spell)
672           vars_removed.emplace_back(var->usr, previous_id_map.primary_file);
673         if (!var->declarations.empty())
674           vars_declarations.push_back(QueryVar::DeclarationsUpdate(
675               previous_id_map.ToQuery(var->id), {},
676               previous_id_map.ToQuery(var->declarations)));
677         if (!var->uses.empty())
678           vars_uses.push_back(
679               QueryVar::UsesUpdate(previous_id_map.ToQuery(var->id), {},
680                                    previous_id_map.ToQuery(var->uses)));
681       },
682       /*onAdded:*/
683       [this, &current_id_map](IndexVar* var) {
684         optional<QueryVar::Def> def_update = ToQuery(current_id_map, var->def);
685         if (def_update)
686           vars_def_update.push_back(
687               QueryVar::DefUpdate(var->usr, std::move(*def_update)));
688         if (!var->declarations.empty())
689           vars_declarations.push_back(QueryVar::DeclarationsUpdate(
690               current_id_map.ToQuery(var->id),
691               current_id_map.ToQuery(var->declarations)));
692         if (!var->uses.empty())
693           vars_uses.push_back(
694               QueryVar::UsesUpdate(current_id_map.ToQuery(var->id),
695                                    current_id_map.ToQuery(var->uses)));
696       },
697       /*onFound:*/
698       [this, &previous_id_map, &current_id_map](IndexVar* previous,
699                                                 IndexVar* current) {
700         optional<QueryVar::Def> previous_remapped_def =
701             ToQuery(previous_id_map, previous->def);
702         optional<QueryVar::Def> current_remapped_def =
703             ToQuery(current_id_map, current->def);
704         if (current_remapped_def &&
705             previous_remapped_def != current_remapped_def &&
706             !current_remapped_def->detailed_name.empty())
707           vars_def_update.push_back(QueryVar::DefUpdate(
708               current->usr, std::move(*current_remapped_def)));
709 
710         PROCESS_UPDATE_DIFF(QueryId::Var, vars_declarations, declarations,
711                             QueryId::LexicalRef);
712         PROCESS_UPDATE_DIFF(QueryId::Var, vars_uses, uses, QueryId::LexicalRef);
713       });
714 
715 #undef PROCESS_UPDATE_DIFF
716 }
717 
718 // This function runs on an indexer thread.
Merge(IndexUpdate && update)719 void IndexUpdate::Merge(IndexUpdate&& update) {
720 #define INDEX_UPDATE_APPEND(name) AddRange(&name, std::move(update.name));
721 #define INDEX_UPDATE_MERGE(name) \
722   AddMergeableRange(&name, std::move(update.name));
723 
724   INDEX_UPDATE_APPEND(files_removed);
725   INDEX_UPDATE_APPEND(files_def_update);
726 
727   INDEX_UPDATE_APPEND(types_removed);
728   INDEX_UPDATE_APPEND(types_def_update);
729   INDEX_UPDATE_MERGE(types_derived);
730   INDEX_UPDATE_MERGE(types_instances);
731   INDEX_UPDATE_MERGE(types_uses);
732 
733   INDEX_UPDATE_APPEND(funcs_removed);
734   INDEX_UPDATE_APPEND(funcs_def_update);
735   INDEX_UPDATE_MERGE(funcs_declarations);
736   INDEX_UPDATE_MERGE(funcs_derived);
737   INDEX_UPDATE_MERGE(funcs_uses);
738 
739   INDEX_UPDATE_APPEND(vars_removed);
740   INDEX_UPDATE_APPEND(vars_def_update);
741   INDEX_UPDATE_MERGE(vars_declarations);
742   INDEX_UPDATE_MERGE(vars_uses);
743 
744 #undef INDEX_UPDATE_APPEND
745 #undef INDEX_UPDATE_MERGE
746 }
747 
ToString()748 std::string IndexUpdate::ToString() {
749   rapidjson::StringBuffer output;
750   rapidjson::Writer<rapidjson::StringBuffer> writer(output);
751   JsonWriter json_writer(&writer);
752   IndexUpdate& update = *this;
753   Reflect(json_writer, update);
754   return output.GetString();
755 }
756 
757 // ------------------------
758 // QUERYDB THREAD FUNCTIONS
759 // ------------------------
760 
RemoveUsrs(SymbolKind usr_kind,const std::vector<Usr> & to_remove)761 void QueryDatabase::RemoveUsrs(SymbolKind usr_kind,
762                                const std::vector<Usr>& to_remove) {
763   // This function runs on the querydb thread.
764 
765   // When we remove an element, we just erase the state from the storage. We do
766   // not update array indices because that would take a huge amount of time for
767   // a very large index.
768   //
769   // There means that there is some memory growth that will never be reclaimed,
770   // but it should be pretty minimal and is solved by simply restarting the
771   // indexer and loading from cache, which is a fast operation.
772   //
773   // TODO: Add "cquery: Reload Index" command which unloads all querydb state
774   // and fully reloads from cache. This will address the memory leak above.
775 
776   switch (usr_kind) {
777     case SymbolKind::Type: {
778       for (const Usr& usr : to_remove) {
779         QueryType& type = types[usr_to_type[usr].id];
780         if (type.symbol_idx)
781           symbols[type.symbol_idx->id].kind = SymbolKind::Invalid;
782         type.def.clear();
783       }
784       break;
785     }
786     default:
787       break;
788   }
789 }
790 
RemoveUsrs(SymbolKind usr_kind,const std::vector<WithUsr<QueryId::File>> & to_remove)791 void QueryDatabase::RemoveUsrs(
792     SymbolKind usr_kind,
793     const std::vector<WithUsr<QueryId::File>>& to_remove) {
794   switch (usr_kind) {
795     case SymbolKind::Func: {
796       for (const auto& usr_file : to_remove) {
797         QueryFunc& func = funcs[usr_to_func[usr_file.usr].id];
798         func.def.remove_if([&](const QueryFunc::Def& def) {
799           return def.file == usr_file.value;
800         });
801       }
802       break;
803     }
804     case SymbolKind::Var: {
805       for (const auto& usr_file : to_remove) {
806         QueryVar& var = vars[usr_to_var[usr_file.usr].id];
807         var.def.remove_if([&](const QueryVar::Def& def) {
808           return def.file == usr_file.value;
809         });
810       }
811       break;
812     }
813     default:
814       assert(false);
815       break;
816   }
817 }
818 
ApplyIndexUpdate(IndexUpdate * update)819 void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
820 // This function runs on the querydb thread.
821 
822 // Example types:
823 //  storage_name       =>  std::vector<optional<QueryType>>
824 //  merge_update       =>  QueryType::DerivedUpdate =>
825 //  MergeableUpdate<QueryId::Type, QueryId::Type> def                =>
826 //  QueryType def->def_var_name  =>  std::vector<QueryId::Type>
827 #define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
828   for (auto merge_update : update->update_var_name) {                 \
829     auto& def = storage_name[merge_update.id.id];                     \
830     AddRange(&def.def_var_name, merge_update.to_add);                 \
831     RemoveRange(&def.def_var_name, merge_update.to_remove);           \
832     VerifyUnique(def.def_var_name);                                   \
833   }
834 
835   for (const AbsolutePath& filename : update->files_removed)
836     files[usr_to_file[filename].id].def = nullopt;
837   ImportOrUpdate(update->files_def_update);
838 
839   RemoveUsrs(SymbolKind::Type, update->types_removed);
840   ImportOrUpdate(std::move(update->types_def_update));
841   HANDLE_MERGEABLE(types_declarations, declarations, types);
842   HANDLE_MERGEABLE(types_derived, derived, types);
843   HANDLE_MERGEABLE(types_instances, instances, types);
844   HANDLE_MERGEABLE(types_uses, uses, types);
845 
846   RemoveUsrs(SymbolKind::Func, update->funcs_removed);
847   ImportOrUpdate(std::move(update->funcs_def_update));
848   HANDLE_MERGEABLE(funcs_declarations, declarations, funcs);
849   HANDLE_MERGEABLE(funcs_derived, derived, funcs);
850   HANDLE_MERGEABLE(funcs_uses, uses, funcs);
851 
852   RemoveUsrs(SymbolKind::Var, update->vars_removed);
853   ImportOrUpdate(std::move(update->vars_def_update));
854   HANDLE_MERGEABLE(vars_declarations, declarations, vars);
855   HANDLE_MERGEABLE(vars_uses, uses, vars);
856 
857 #undef HANDLE_MERGEABLE
858 }
859 
ImportOrUpdate(const std::vector<QueryFile::DefUpdate> & updates)860 void QueryDatabase::ImportOrUpdate(
861     const std::vector<QueryFile::DefUpdate>& updates) {
862   // This function runs on the querydb thread.
863 
864   for (auto& def : updates) {
865     auto it = usr_to_file.find(def.value.path);
866     assert(it != usr_to_file.end());
867 
868     QueryFile& existing = files[it->second.id];
869 
870     existing.def = def.value;
871     UpdateSymbols(&existing.symbol_idx, SymbolKind::File, it->second);
872   }
873 }
874 
ImportOrUpdate(std::vector<QueryType::DefUpdate> && updates)875 void QueryDatabase::ImportOrUpdate(
876     std::vector<QueryType::DefUpdate>&& updates) {
877   // This function runs on the querydb thread.
878 
879   for (auto& def : updates) {
880     assert(!def.value.detailed_name.empty());
881 
882     auto it = usr_to_type.find(def.usr);
883     assert(it != usr_to_type.end());
884 
885     assert(it->second.id >= 0 && it->second.id < types.size());
886     QueryType& existing = types[it->second.id];
887     if (!TryReplaceDef(existing.def, std::move(def.value))) {
888       existing.def.push_front(std::move(def.value));
889       UpdateSymbols(&existing.symbol_idx, SymbolKind::Type, it->second);
890     }
891   }
892 }
893 
ImportOrUpdate(std::vector<QueryFunc::DefUpdate> && updates)894 void QueryDatabase::ImportOrUpdate(
895     std::vector<QueryFunc::DefUpdate>&& updates) {
896   // This function runs on the querydb thread.
897 
898   for (auto& def : updates) {
899     assert(!def.value.detailed_name.empty());
900 
901     auto it = usr_to_func.find(def.usr);
902     assert(it != usr_to_func.end());
903 
904     assert(it->second.id >= 0 && it->second.id < funcs.size());
905     QueryFunc& existing = funcs[it->second.id];
906     if (!TryReplaceDef(existing.def, std::move(def.value))) {
907       existing.def.push_front(std::move(def.value));
908       UpdateSymbols(&existing.symbol_idx, SymbolKind::Func, it->second);
909     }
910   }
911 }
912 
ImportOrUpdate(std::vector<QueryVar::DefUpdate> && updates)913 void QueryDatabase::ImportOrUpdate(std::vector<QueryVar::DefUpdate>&& updates) {
914   // This function runs on the querydb thread.
915 
916   for (auto& def : updates) {
917     assert(!def.value.detailed_name.empty());
918 
919     auto it = usr_to_var.find(def.usr);
920     assert(it != usr_to_var.end());
921 
922     assert(it->second.id >= 0 && it->second.id < vars.size());
923     QueryVar& existing = vars[it->second.id];
924     if (!TryReplaceDef(existing.def, std::move(def.value))) {
925       existing.def.push_front(std::move(def.value));
926       if (!existing.def.front().is_local())
927         UpdateSymbols(&existing.symbol_idx, SymbolKind::Var, it->second);
928     }
929   }
930 }
931 
UpdateSymbols(Maybe<AnyId> * symbol_idx,SymbolKind kind,AnyId idx)932 void QueryDatabase::UpdateSymbols(Maybe<AnyId>* symbol_idx,
933                                   SymbolKind kind,
934                                   AnyId idx) {
935   if (!symbol_idx->HasValue()) {
936     *symbol_idx = AnyId(symbols.size());
937     symbols.push_back(SymbolIdx{idx, kind});
938   }
939 }
940 
941 // For Func, the returned name does not include parameters.
GetSymbolDetailedName(RawId symbol_idx) const942 std::string_view QueryDatabase::GetSymbolDetailedName(RawId symbol_idx) const {
943   RawId idx = symbols[symbol_idx].id.id;
944   switch (symbols[symbol_idx].kind) {
945     default:
946       break;
947     case SymbolKind::File:
948       if (files[idx].def)
949         return files[idx].def->path.path;
950       break;
951     case SymbolKind::Func:
952       if (const auto* def = funcs[idx].AnyDef())
953         return def->DetailedName(false);
954       break;
955     case SymbolKind::Type:
956       if (const auto* def = types[idx].AnyDef())
957         return def->detailed_name;
958       break;
959     case SymbolKind::Var:
960       if (const auto* def = vars[idx].AnyDef())
961         return def->detailed_name;
962       break;
963   }
964   return "";
965 }
966 
GetSymbolShortName(RawId symbol_idx) const967 std::string_view QueryDatabase::GetSymbolShortName(RawId symbol_idx) const {
968   RawId idx = symbols[symbol_idx].id.id;
969   switch (symbols[symbol_idx].kind) {
970     default:
971       break;
972     case SymbolKind::File:
973       if (files[idx].def)
974         return files[idx].def->path.path;
975       break;
976     case SymbolKind::Func:
977       if (const auto* def = funcs[idx].AnyDef())
978         return def->ShortName();
979       break;
980     case SymbolKind::Type:
981       if (const auto* def = types[idx].AnyDef())
982         return def->ShortName();
983       break;
984     case SymbolKind::Var:
985       if (const auto* def = vars[idx].AnyDef())
986         return def->ShortName();
987       break;
988   }
989   return "";
990 }
991 
992 TEST_SUITE("query") {
GetDelta(IndexFile previous,IndexFile current)993   IndexUpdate GetDelta(IndexFile previous, IndexFile current) {
994     QueryDatabase db;
995     IdMap previous_map(&db, previous.id_cache);
996     IdMap current_map(&db, current.id_cache);
997     return IndexUpdate::CreateDelta(&previous_map, &current_map, &previous,
998                                     &current);
999   }
1000 
1001   TEST_CASE("remove defs") {
1002     IndexFile previous(AbsolutePath("foo.cc"), "<empty>");
1003     IndexFile current(AbsolutePath("foo.cc"), "<empty>");
1004 
1005     previous.Resolve(previous.ToTypeId(HashUsr("usr1")))->def.spell =
1006         IndexId::LexicalRef(Range(Position(1, 0)), {}, {}, {});
1007     previous.Resolve(previous.ToFuncId(HashUsr("usr2")))->def.spell =
1008         IndexId::LexicalRef(Range(Position(2, 0)), {}, {}, {});
1009     previous.Resolve(previous.ToVarId(HashUsr("usr3")))->def.spell =
1010         IndexId::LexicalRef(Range(Position(3, 0)), {}, {}, {});
1011 
1012     IndexUpdate update = GetDelta(previous, current);
1013 
1014     REQUIRE(update.types_removed == std::vector<Usr>{HashUsr("usr1")});
1015     REQUIRE(update.funcs_removed.size() == 1);
1016     REQUIRE(update.funcs_removed[0].usr == HashUsr("usr2"));
1017     REQUIRE(update.vars_removed.size() == 1);
1018     REQUIRE(update.vars_removed[0].usr == HashUsr("usr3"));
1019   }
1020 
1021   TEST_CASE("do not remove ref-only defs") {
1022     IndexFile previous(AbsolutePath("foo.cc"), "<empty>");
1023     IndexFile current(AbsolutePath("foo.cc"), "<empty>");
1024 
1025     previous.Resolve(previous.ToTypeId(HashUsr("usr1")))
1026         ->uses.push_back(
1027             IndexId::LexicalRef(Range(Position(1, 0)), AnyId(0), SymbolKind::Func, {}));
1028     previous.Resolve(previous.ToFuncId(HashUsr("usr2")))
1029         ->uses.push_back(
1030             IndexId::LexicalRef(Range(Position(2, 0)), AnyId(0), SymbolKind::Func, {}));
1031     previous.Resolve(previous.ToVarId(HashUsr("usr3")))
1032         ->uses.push_back(
1033             IndexId::LexicalRef(Range(Position(3, 0)), AnyId(0), SymbolKind::Func, {}));
1034 
1035     IndexUpdate update = GetDelta(previous, current);
1036 
1037     REQUIRE(update.types_removed == std::vector<Usr>{});
1038     REQUIRE(update.funcs_removed.empty());
1039     REQUIRE(update.vars_removed.empty());
1040   }
1041 
1042   TEST_CASE("func callers") {
1043     IndexFile previous(AbsolutePath("foo.cc"), "<empty>");
1044     IndexFile current(AbsolutePath("foo.cc"), "<empty>");
1045 
1046     IndexFunc* pf = previous.Resolve(previous.ToFuncId(HashUsr("usr")));
1047     IndexFunc* cf = current.Resolve(current.ToFuncId(HashUsr("usr")));
1048 
1049     pf->uses.push_back(IndexId::LexicalRef(Range(Position(1, 0)), AnyId(0), SymbolKind::Func, {}));
1050     cf->uses.push_back(IndexId::LexicalRef(Range(Position(2, 0)), AnyId(0), SymbolKind::Func, {}));
1051 
1052     IndexUpdate update = GetDelta(previous, current);
1053 
1054     REQUIRE(update.funcs_removed.empty());
1055     REQUIRE(update.funcs_uses.size() == 1);
1056     REQUIRE(update.funcs_uses[0].id == QueryId::Func(0));
1057     REQUIRE(update.funcs_uses[0].to_remove.size() == 1);
1058     REQUIRE(update.funcs_uses[0].to_remove[0].range == Range(Position(1, 0)));
1059     REQUIRE(update.funcs_uses[0].to_add.size() == 1);
1060     REQUIRE(update.funcs_uses[0].to_add[0].range == Range(Position(2, 0)));
1061   }
1062 
1063   TEST_CASE("type usages") {
1064     IndexFile previous(AbsolutePath("foo.cc"), "<empty>");
1065     IndexFile current(AbsolutePath("foo.cc"), "<empty>");
1066 
1067     IndexType* pt = previous.Resolve(previous.ToTypeId(HashUsr("usr")));
1068     IndexType* ct = current.Resolve(current.ToTypeId(HashUsr("usr")));
1069 
1070     pt->uses.push_back(IndexId::LexicalRef(Range(Position(1, 0)), AnyId(0), SymbolKind::Type, {}));
1071     ct->uses.push_back(IndexId::LexicalRef(Range(Position(2, 0)), AnyId(0), SymbolKind::Type, {}));
1072 
1073     IndexUpdate update = GetDelta(previous, current);
1074 
1075     REQUIRE(update.types_removed == std::vector<Usr>{});
1076     REQUIRE(update.types_def_update.empty());
1077     REQUIRE(update.types_uses.size() == 1);
1078     REQUIRE(update.types_uses[0].to_remove.size() == 1);
1079     REQUIRE(update.types_uses[0].to_remove[0].range == Range(Position(1, 0)));
1080     REQUIRE(update.types_uses[0].to_add.size() == 1);
1081     REQUIRE(update.types_uses[0].to_add[0].range == Range(Position(2, 0)));
1082   }
1083 
1084   TEST_CASE("apply delta") {
1085     IndexFile previous(AbsolutePath("foo.cc"), "<empty>");
1086     IndexFile current(AbsolutePath("foo.cc"), "<empty>");
1087 
1088     IndexFunc* pf = previous.Resolve(previous.ToFuncId(HashUsr("usr")));
1089     IndexFunc* cf = current.Resolve(current.ToFuncId(HashUsr("usr")));
1090     pf->uses.push_back(IndexId::LexicalRef(Range(Position(1, 0)), AnyId(0), SymbolKind::Func, {}));
1091     pf->uses.push_back(IndexId::LexicalRef(Range(Position(2, 0)), AnyId(0), SymbolKind::Func, {}));
1092     cf->uses.push_back(IndexId::LexicalRef(Range(Position(4, 0)), AnyId(0), SymbolKind::Func, {}));
1093     cf->uses.push_back(IndexId::LexicalRef(Range(Position(5, 0)), AnyId(0), SymbolKind::Func, {}));
1094 
1095     QueryDatabase db;
1096     IdMap previous_map(&db, previous.id_cache);
1097     IdMap current_map(&db, current.id_cache);
1098     REQUIRE(db.funcs.size() == 1);
1099 
1100     IndexUpdate import_update =
1101         IndexUpdate::CreateDelta(nullptr, &previous_map, nullptr, &previous);
1102     IndexUpdate delta_update = IndexUpdate::CreateDelta(
1103         &previous_map, &current_map, &previous, &current);
1104 
1105     db.ApplyIndexUpdate(&import_update);
1106     REQUIRE(db.funcs[0].uses.size() == 2);
1107     REQUIRE(db.funcs[0].uses[0].range == Range(Position(1, 0)));
1108     REQUIRE(db.funcs[0].uses[1].range == Range(Position(2, 0)));
1109 
1110     db.ApplyIndexUpdate(&delta_update);
1111     REQUIRE(db.funcs[0].uses.size() == 2);
1112     REQUIRE(db.funcs[0].uses[0].range == Range(Position(4, 0)));
1113     REQUIRE(db.funcs[0].uses[1].range == Range(Position(5, 0)));
1114   }
1115 
1116   TEST_CASE("Remove variable with usage") {
__anon6772d7021302(const char* json) 1117     auto load_index_from_json = [](const char* json) {
1118       return Deserialize(SerializeFormat::Json,
1119                          AbsolutePath::BuildDoNotUse("foo.cc"), json, "<empty>",
1120                          nullopt);
1121     };
1122 
1123     auto previous = load_index_from_json(R"RAW(
1124 {
1125   "types": [
1126     {
1127       "id": 0,
1128       "usr": 17,
1129       "detailed_name": "",
1130       "short_name_offset": 0,
1131       "short_name_size": 0,
1132       "kind": 0,
1133       "hover": "",
1134       "comments": "",
1135       "parents": [],
1136       "derived": [],
1137       "types": [],
1138       "funcs": [],
1139       "vars": [],
1140       "instances": [
1141         0
1142       ],
1143       "uses": []
1144     }
1145   ],
1146   "funcs": [
1147     {
1148       "id": 0,
1149       "usr": 4259594751088586730,
1150       "detailed_name": "void foo()",
1151       "short_name_offset": 5,
1152       "short_name_size": 3,
1153       "kind": 12,
1154       "storage": 1,
1155       "hover": "",
1156       "comments": "",
1157       "declarations": [],
1158       "spell": "1:6-1:9|-1|1|2",
1159       "extent": "1:1-4:2|-1|1|0",
1160       "base": [],
1161       "derived": [],
1162       "locals": [],
1163       "uses": [],
1164       "callees": []
1165     }
1166   ],
1167   "vars": [
1168     {
1169       "id": 0,
1170       "usr": 16837348799350457167,
1171       "detailed_name": "int a",
1172       "short_name_offset": 4,
1173       "short_name_size": 1,
1174       "hover": "",
1175       "comments": "",
1176       "declarations": [],
1177       "spell": "2:7-2:8|0|3|2",
1178       "extent": "2:3-2:8|0|3|2",
1179       "type": 0,
1180       "uses": [
1181         "3:3-3:4|0|3|4"
1182       ],
1183       "kind": 13,
1184       "storage": 1
1185     }
1186   ]
1187 }
1188     )RAW");
1189 
1190     auto current = load_index_from_json(R"RAW(
1191 {
1192   "types": [],
1193   "funcs": [
1194     {
1195       "id": 0,
1196       "usr": 4259594751088586730,
1197       "detailed_name": "void foo()",
1198       "short_name_offset": 5,
1199       "short_name_size": 3,
1200       "kind": 12,
1201       "storage": 1,
1202       "hover": "",
1203       "comments": "",
1204       "declarations": [],
1205       "spell": "1:6-1:9|-1|1|2",
1206       "extent": "1:1-5:2|-1|1|0",
1207       "base": [],
1208       "derived": [],
1209       "locals": [],
1210       "uses": [],
1211       "callees": []
1212     }
1213   ],
1214   "vars": []
1215 }
1216     )RAW");
1217 
1218     // Validate previous/current were parsed.
1219     REQUIRE(previous->vars.size() == 1);
1220     REQUIRE(current->vars.size() == 0);
1221 
1222     QueryDatabase db;
1223 
1224     // Apply initial file.
1225     {
1226       IdMap previous_map(&db, previous->id_cache);
1227       IndexUpdate import_update = IndexUpdate::CreateDelta(
1228           nullptr, &previous_map, nullptr, previous.get());
1229       db.ApplyIndexUpdate(&import_update);
1230     }
1231 
1232     REQUIRE(db.vars.size() == 1);
1233     REQUIRE(db.vars[0].uses.size() == 1);
1234 
1235     // Apply change.
1236     {
1237       IdMap previous_map(&db, previous->id_cache);
1238       IdMap current_map(&db, current->id_cache);
1239       IndexUpdate delta_update = IndexUpdate::CreateDelta(
1240           &previous_map, &current_map, previous.get(), current.get());
1241       db.ApplyIndexUpdate(&delta_update);
1242     }
1243     REQUIRE(db.vars.size() == 1);
1244     REQUIRE(db.vars[0].uses.size() == 0);
1245   }
1246 }
1247