1 //===- CompilationDatabase.cpp - LSP Compilation Database -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CompilationDatabase.h" 10 #include "../lsp-server-support/Logging.h" 11 #include "Protocol.h" 12 #include "mlir/Support/FileUtilities.h" 13 #include "llvm/ADT/SetVector.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Support/YAMLTraits.h" 16 17 using namespace mlir; 18 using namespace mlir::lsp; 19 20 //===----------------------------------------------------------------------===// 21 // YamlFileInfo 22 //===----------------------------------------------------------------------===// 23 24 namespace { 25 struct YamlFileInfo { 26 /// The absolute path to the file. 27 std::string filename; 28 /// The include directories available for the file. 29 std::vector<std::string> includeDirs; 30 }; 31 } // namespace 32 33 //===----------------------------------------------------------------------===// 34 // CompilationDatabase 35 //===----------------------------------------------------------------------===// 36 37 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(YamlFileInfo) 38 39 namespace llvm { 40 namespace yaml { 41 template <> 42 struct MappingTraits<YamlFileInfo> { 43 static void mapping(IO &io, YamlFileInfo &info) { 44 // Parse the filename and normalize it to the form we will expect from 45 // incoming URIs. 46 io.mapRequired("filepath", info.filename); 47 48 // Normalize the filename to avoid incompatability with incoming URIs. 49 if (Expected<lsp::URIForFile> uri = 50 lsp::URIForFile::fromFile(info.filename)) 51 info.filename = uri->file().str(); 52 53 // Parse the includes from the yaml stream. These are in the form of a 54 // semi-colon delimited list. 55 std::string combinedIncludes; 56 io.mapRequired("includes", combinedIncludes); 57 for (StringRef include : llvm::split(combinedIncludes, ";")) { 58 if (!include.empty()) 59 info.includeDirs.push_back(include.str()); 60 } 61 } 62 }; 63 } // end namespace yaml 64 } // end namespace llvm 65 66 CompilationDatabase::CompilationDatabase(ArrayRef<std::string> databases) { 67 for (StringRef filename : databases) 68 loadDatabase(filename); 69 } 70 71 const CompilationDatabase::FileInfo & 72 CompilationDatabase::getFileInfo(StringRef filename) const { 73 auto it = files.find(filename); 74 return it == files.end() ? defaultFileInfo : it->second; 75 } 76 77 void CompilationDatabase::loadDatabase(StringRef filename) { 78 if (filename.empty()) 79 return; 80 81 // Set up the input file. 82 std::string errorMessage; 83 std::unique_ptr<llvm::MemoryBuffer> inputFile = 84 openInputFile(filename, &errorMessage); 85 if (!inputFile) { 86 Logger::error("Failed to open compilation database: {0}", errorMessage); 87 return; 88 } 89 llvm::yaml::Input yaml(inputFile->getBuffer()); 90 91 // Parse the yaml description and add any new files to the database. 92 std::vector<YamlFileInfo> parsedFiles; 93 yaml >> parsedFiles; 94 95 SetVector<StringRef> knownIncludes; 96 for (auto &file : parsedFiles) { 97 auto it = files.try_emplace(file.filename, std::move(file.includeDirs)); 98 99 // If we encounter a duplicate file, log a warning and ignore it. 100 if (!it.second) { 101 Logger::info("Duplicate file in compilation database: {0}", 102 file.filename); 103 continue; 104 } 105 106 // Track the includes for the file. 107 for (StringRef include : it.first->second.includeDirs) 108 knownIncludes.insert(include); 109 } 110 111 // Add all of the known includes to the default file info. We don't know any 112 // information about how to treat these files, but these may be project files 113 // that we just don't yet have information for. In these cases, providing some 114 // heuristic information provides a better user experience, and generally 115 // shouldn't lead to any negative side effects. 116 for (StringRef include : knownIncludes) 117 defaultFileInfo.includeDirs.push_back(include.str()); 118 } 119