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