1 //===--- FileIndex.cpp - Indexes for files. ------------------------ C++-*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "FileIndex.h"
11 #include "SymbolCollector.h"
12 #include "clang/Index/IndexingAction.h"
13 
14 namespace clang {
15 namespace clangd {
16 namespace {
17 
18 /// Retrieves namespace and class level symbols in \p Decls.
19 std::unique_ptr<SymbolSlab> indexAST(ASTContext &Ctx,
20                                      std::shared_ptr<Preprocessor> PP,
21                                      llvm::ArrayRef<const Decl *> Decls) {
22   SymbolCollector::Options CollectorOpts;
23   // Although we do not index symbols in main files (e.g. cpp file), information
24   // in main files like definition locations of class declarations will still be
25   // collected; thus, the index works for go-to-definition.
26   // FIXME(ioeric): get rid of `IndexMainFiles` as this is always set to false.
27   CollectorOpts.IndexMainFiles = false;
28   // FIXME(ioeric): we might also want to collect include headers. We would need
29   // to make sure all includes are canonicalized (with CanonicalIncludes), which
30   // is not trivial given the current way of collecting symbols: we only have
31   // AST at this point, but we also need preprocessor callbacks (e.g.
32   // CommentHandler for IWYU pragma) to canonicalize includes.
33   CollectorOpts.CollectIncludePath = false;
34 
35   auto Collector = std::make_shared<SymbolCollector>(std::move(CollectorOpts));
36   Collector->setPreprocessor(std::move(PP));
37   index::IndexingOptions IndexOpts;
38   IndexOpts.SystemSymbolFilter =
39       index::IndexingOptions::SystemSymbolFilterKind::All;
40   IndexOpts.IndexFunctionLocals = false;
41 
42   index::indexTopLevelDecls(Ctx, Decls, Collector, IndexOpts);
43   auto Symbols = llvm::make_unique<SymbolSlab>();
44   *Symbols = Collector->takeSymbols();
45   return Symbols;
46 }
47 
48 } // namespace
49 
50 void FileSymbols::update(PathRef Path, std::unique_ptr<SymbolSlab> Slab) {
51   std::lock_guard<std::mutex> Lock(Mutex);
52   if (!Slab)
53     FileToSlabs.erase(Path);
54   else
55     FileToSlabs[Path] = std::move(Slab);
56 }
57 
58 std::shared_ptr<std::vector<const Symbol *>> FileSymbols::allSymbols() {
59   // The snapshot manages life time of symbol slabs and provides pointers of all
60   // symbols in all slabs.
61   struct Snapshot {
62     std::vector<const Symbol *> Pointers;
63     std::vector<std::shared_ptr<SymbolSlab>> KeepAlive;
64   };
65   auto Snap = std::make_shared<Snapshot>();
66   {
67     std::lock_guard<std::mutex> Lock(Mutex);
68 
69     for (const auto &FileAndSlab : FileToSlabs) {
70       Snap->KeepAlive.push_back(FileAndSlab.second);
71       for (const auto &Iter : *FileAndSlab.second)
72         Snap->Pointers.push_back(&Iter);
73     }
74   }
75   auto *Pointers = &Snap->Pointers;
76   // Use aliasing constructor to keep the snapshot alive along with the
77   // pointers.
78   return {std::move(Snap), Pointers};
79 }
80 
81 void FileIndex::update(PathRef Path, ParsedAST *AST) {
82   if (!AST) {
83     FSymbols.update(Path, nullptr);
84   } else {
85     auto Slab = indexAST(AST->getASTContext(), AST->getPreprocessorPtr(),
86                          AST->getTopLevelDecls());
87     FSymbols.update(Path, std::move(Slab));
88   }
89   auto Symbols = FSymbols.allSymbols();
90   Index.build(std::move(Symbols));
91 }
92 
93 bool FileIndex::fuzzyFind(
94     const FuzzyFindRequest &Req,
95     llvm::function_ref<void(const Symbol &)> Callback) const {
96   return Index.fuzzyFind(Req, Callback);
97 }
98 
99 } // namespace clangd
100 } // namespace clang
101