Kirill Bobyrev | 8e35f1e | 2018-08-14 16:03:32 +0000 | [diff] [blame] | 1 | //===--- GlobalCompilationDatabase.cpp ---------------------------*- C++-*-===// |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 6 | // |
Kirill Bobyrev | 8e35f1e | 2018-08-14 16:03:32 +0000 | [diff] [blame] | 7 | //===----------------------------------------------------------------------===// |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 8 | |
| 9 | #include "GlobalCompilationDatabase.h" |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 10 | #include "FS.h" |
Ilya Biryukov | 0c1ca6b | 2017-10-02 15:13:20 +0000 | [diff] [blame] | 11 | #include "Logger.h" |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 12 | #include "Path.h" |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 13 | #include "clang/Frontend/CompilerInvocation.h" |
| 14 | #include "clang/Tooling/ArgumentsAdjusters.h" |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 15 | #include "clang/Tooling/CompilationDatabase.h" |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 16 | #include "llvm/ADT/None.h" |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/Optional.h" |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/STLExtras.h" |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 19 | #include "llvm/ADT/SmallString.h" |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 20 | #include "llvm/Support/FileSystem.h" |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame] | 21 | #include "llvm/Support/FileUtilities.h" |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 22 | #include "llvm/Support/Path.h" |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame] | 23 | #include "llvm/Support/Program.h" |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 24 | #include <string> |
| 25 | #include <tuple> |
| 26 | #include <vector> |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 27 | |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 28 | namespace clang { |
| 29 | namespace clangd { |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 30 | namespace { |
| 31 | |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 32 | // Runs the given action on all parent directories of filename, starting from |
| 33 | // deepest directory and going up to root. Stops whenever action succeeds. |
| 34 | void actOnAllParentDirectories(PathRef FileName, |
| 35 | llvm::function_ref<bool(PathRef)> Action) { |
| 36 | for (auto Path = llvm::sys::path::parent_path(FileName); |
| 37 | !Path.empty() && !Action(Path); |
| 38 | Path = llvm::sys::path::parent_path(Path)) |
| 39 | ; |
| 40 | } |
| 41 | |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 42 | } // namespace |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 43 | |
Sam McCall | ecbeab0 | 2017-12-04 10:08:45 +0000 | [diff] [blame] | 44 | tooling::CompileCommand |
| 45 | GlobalCompilationDatabase::getFallbackCommand(PathRef File) const { |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame] | 46 | std::vector<std::string> Argv = {"clang"}; |
Haojian Wu | 8ddf31b | 2019-06-18 11:54:17 +0000 | [diff] [blame] | 47 | // Clang treats .h files as C by default and files without extension as linker |
| 48 | // input, resulting in unhelpful diagnostics. |
Sam McCall | 690dcf1 | 2018-04-20 11:35:17 +0000 | [diff] [blame] | 49 | // Parsing as Objective C++ is friendly to more cases. |
Haojian Wu | 8ddf31b | 2019-06-18 11:54:17 +0000 | [diff] [blame] | 50 | auto FileExtension = llvm::sys::path::extension(File); |
| 51 | if (FileExtension.empty() || FileExtension == ".h") |
Sam McCall | 690dcf1 | 2018-04-20 11:35:17 +0000 | [diff] [blame] | 52 | Argv.push_back("-xobjective-c++-header"); |
Benjamin Kramer | adcd026 | 2020-01-28 20:23:46 +0100 | [diff] [blame] | 53 | Argv.push_back(std::string(File)); |
Eric Liu | 9ef03dd | 2019-04-15 12:32:28 +0000 | [diff] [blame] | 54 | tooling::CompileCommand Cmd(llvm::sys::path::parent_path(File), |
| 55 | llvm::sys::path::filename(File), std::move(Argv), |
| 56 | /*Output=*/""); |
| 57 | Cmd.Heuristic = "clangd fallback"; |
| 58 | return Cmd; |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 59 | } |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 60 | |
Ilya Biryukov | e5128f7 | 2017-09-20 07:24:15 +0000 | [diff] [blame] | 61 | DirectoryBasedGlobalCompilationDatabase:: |
Ilya Biryukov | f2001aa | 2019-01-07 15:45:19 +0000 | [diff] [blame] | 62 | DirectoryBasedGlobalCompilationDatabase( |
| 63 | llvm::Optional<Path> CompileCommandsDir) |
Ilya Biryukov | 940901e | 2017-12-13 12:51:22 +0000 | [diff] [blame] | 64 | : CompileCommandsDir(std::move(CompileCommandsDir)) {} |
Ilya Biryukov | e5128f7 | 2017-09-20 07:24:15 +0000 | [diff] [blame] | 65 | |
Sam McCall | 690dcf1 | 2018-04-20 11:35:17 +0000 | [diff] [blame] | 66 | DirectoryBasedGlobalCompilationDatabase:: |
| 67 | ~DirectoryBasedGlobalCompilationDatabase() = default; |
| 68 | |
Ilya Biryukov | f2001aa | 2019-01-07 15:45:19 +0000 | [diff] [blame] | 69 | llvm::Optional<tooling::CompileCommand> |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 70 | DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const { |
| 71 | CDBLookupRequest Req; |
| 72 | Req.FileName = File; |
| 73 | Req.ShouldBroadcast = true; |
| 74 | |
| 75 | auto Res = lookupCDB(Req); |
| 76 | if (!Res) { |
Sam McCall | bed5885 | 2018-07-11 10:35:11 +0000 | [diff] [blame] | 77 | log("Failed to find compilation database for {0}", File); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 78 | return llvm::None; |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 79 | } |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 80 | |
| 81 | auto Candidates = Res->CDB->getCompileCommands(File); |
| 82 | if (!Candidates.empty()) |
| 83 | return std::move(Candidates.front()); |
| 84 | |
Sam McCall | c008af6 | 2018-10-20 15:30:37 +0000 | [diff] [blame] | 85 | return None; |
Sam McCall | ecbeab0 | 2017-12-04 10:08:45 +0000 | [diff] [blame] | 86 | } |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 87 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 88 | // For platforms where paths are case-insensitive (but case-preserving), |
| 89 | // we need to do case-insensitive comparisons and use lowercase keys. |
| 90 | // FIXME: Make Path a real class with desired semantics instead. |
| 91 | // This class is not the only place this problem exists. |
| 92 | // FIXME: Mac filesystems default to case-insensitive, but may be sensitive. |
| 93 | |
| 94 | static std::string maybeCaseFoldPath(PathRef Path) { |
| 95 | #if defined(_WIN32) || defined(__APPLE__) |
| 96 | return Path.lower(); |
| 97 | #else |
Benjamin Kramer | adcd026 | 2020-01-28 20:23:46 +0100 | [diff] [blame] | 98 | return std::string(Path); |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 99 | #endif |
| 100 | } |
| 101 | |
| 102 | static bool pathEqual(PathRef A, PathRef B) { |
| 103 | #if defined(_WIN32) || defined(__APPLE__) |
| 104 | return A.equals_lower(B); |
| 105 | #else |
| 106 | return A == B; |
| 107 | #endif |
| 108 | } |
| 109 | |
| 110 | DirectoryBasedGlobalCompilationDatabase::CachedCDB & |
Sam McCall | c02ba72 | 2017-12-22 09:47:34 +0000 | [diff] [blame] | 111 | DirectoryBasedGlobalCompilationDatabase::getCDBInDirLocked(PathRef Dir) const { |
| 112 | // FIXME(ibiryukov): Invalidate cached compilation databases on changes |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 113 | // FIXME(sammccall): this function hot, avoid copying key when hitting cache. |
| 114 | auto Key = maybeCaseFoldPath(Dir); |
| 115 | auto R = CompilationDatabases.try_emplace(Key); |
| 116 | if (R.second) { // Cache miss, try to load CDB. |
| 117 | CachedCDB &Entry = R.first->second; |
Kadir Cetinkaya | 4fb1adc | 2020-01-29 11:54:22 +0100 | [diff] [blame^] | 118 | std::string Error; |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 119 | Entry.CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error); |
Benjamin Kramer | adcd026 | 2020-01-28 20:23:46 +0100 | [diff] [blame] | 120 | Entry.Path = std::string(Dir); |
Kadir Cetinkaya | 4fb1adc | 2020-01-29 11:54:22 +0100 | [diff] [blame^] | 121 | if (Entry.CDB) |
| 122 | log("Loaded compilation database from {0}", Dir); |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 123 | } |
| 124 | return R.first->second; |
Sam McCall | c02ba72 | 2017-12-22 09:47:34 +0000 | [diff] [blame] | 125 | } |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 126 | |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 127 | llvm::Optional<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult> |
| 128 | DirectoryBasedGlobalCompilationDatabase::lookupCDB( |
| 129 | CDBLookupRequest Request) const { |
| 130 | assert(llvm::sys::path::is_absolute(Request.FileName) && |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 131 | "path must be absolute"); |
| 132 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 133 | bool ShouldBroadcast = false; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 134 | CDBLookupResult Result; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 135 | |
| 136 | { |
| 137 | std::lock_guard<std::mutex> Lock(Mutex); |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 138 | CachedCDB *Entry = nullptr; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 139 | if (CompileCommandsDir) { |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 140 | Entry = &getCDBInDirLocked(*CompileCommandsDir); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 141 | } else { |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 142 | // Traverse the canonical version to prevent false positives. i.e.: |
| 143 | // src/build/../a.cc can detect a CDB in /src/build if not canonicalized. |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 144 | // FIXME(sammccall): this loop is hot, use a union-find-like structure. |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 145 | actOnAllParentDirectories(removeDots(Request.FileName), |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 146 | [&](PathRef Path) { |
| 147 | Entry = &getCDBInDirLocked(Path); |
| 148 | return Entry->CDB != nullptr; |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 149 | }); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 150 | } |
| 151 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 152 | if (!Entry || !Entry->CDB) |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 153 | return llvm::None; |
| 154 | |
| 155 | // Mark CDB as broadcasted to make sure discovery is performed once. |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 156 | if (Request.ShouldBroadcast && !Entry->SentBroadcast) { |
| 157 | Entry->SentBroadcast = true; |
| 158 | ShouldBroadcast = true; |
| 159 | } |
| 160 | |
| 161 | Result.CDB = Entry->CDB.get(); |
| 162 | Result.PI.SourceRoot = Entry->Path; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | // FIXME: Maybe make the following part async, since this can block retrieval |
| 166 | // of compile commands. |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 167 | if (ShouldBroadcast) |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 168 | broadcastCDB(Result); |
| 169 | return Result; |
| 170 | } |
| 171 | |
| 172 | void DirectoryBasedGlobalCompilationDatabase::broadcastCDB( |
| 173 | CDBLookupResult Result) const { |
| 174 | assert(Result.CDB && "Trying to broadcast an invalid CDB!"); |
| 175 | |
| 176 | std::vector<std::string> AllFiles = Result.CDB->getAllFiles(); |
| 177 | // We assume CDB in CompileCommandsDir owns all of its entries, since we don't |
| 178 | // perform any search in parent paths whenever it is set. |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 179 | if (CompileCommandsDir) { |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 180 | assert(*CompileCommandsDir == Result.PI.SourceRoot && |
| 181 | "Trying to broadcast a CDB outside of CompileCommandsDir!"); |
| 182 | OnCommandChanged.broadcast(std::move(AllFiles)); |
| 183 | return; |
| 184 | } |
| 185 | |
| 186 | llvm::StringMap<bool> DirectoryHasCDB; |
| 187 | { |
| 188 | std::lock_guard<std::mutex> Lock(Mutex); |
| 189 | // Uniquify all parent directories of all files. |
| 190 | for (llvm::StringRef File : AllFiles) { |
| 191 | actOnAllParentDirectories(File, [&](PathRef Path) { |
| 192 | auto It = DirectoryHasCDB.try_emplace(Path); |
| 193 | // Already seen this path, and all of its parents. |
| 194 | if (!It.second) |
| 195 | return true; |
| 196 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 197 | CachedCDB &Entry = getCDBInDirLocked(Path); |
| 198 | It.first->second = Entry.CDB != nullptr; |
| 199 | return pathEqual(Path, Result.PI.SourceRoot); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 200 | }); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 201 | } |
| 202 | } |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 203 | |
| 204 | std::vector<std::string> GovernedFiles; |
| 205 | for (llvm::StringRef File : AllFiles) { |
| 206 | // A file is governed by this CDB if lookup for the file would find it. |
| 207 | // Independent of whether it has an entry for that file or not. |
| 208 | actOnAllParentDirectories(File, [&](PathRef Path) { |
| 209 | if (DirectoryHasCDB.lookup(Path)) { |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 210 | if (pathEqual(Path, Result.PI.SourceRoot)) |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 211 | // Make sure listeners always get a canonical path for the file. |
| 212 | GovernedFiles.push_back(removeDots(File)); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 213 | // Stop as soon as we hit a CDB. |
| 214 | return true; |
| 215 | } |
| 216 | return false; |
| 217 | }); |
| 218 | } |
| 219 | |
| 220 | OnCommandChanged.broadcast(std::move(GovernedFiles)); |
| 221 | } |
| 222 | |
| 223 | llvm::Optional<ProjectInfo> |
| 224 | DirectoryBasedGlobalCompilationDatabase::getProjectInfo(PathRef File) const { |
| 225 | CDBLookupRequest Req; |
| 226 | Req.FileName = File; |
| 227 | Req.ShouldBroadcast = false; |
| 228 | auto Res = lookupCDB(Req); |
| 229 | if (!Res) |
| 230 | return llvm::None; |
| 231 | return Res->PI; |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base, |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 235 | std::vector<std::string> FallbackFlags, |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame] | 236 | tooling::ArgumentsAdjuster Adjuster) |
| 237 | : Base(Base), ArgsAdjuster(std::move(Adjuster)), |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 238 | FallbackFlags(std::move(FallbackFlags)) { |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 239 | if (Base) |
| 240 | BaseChanged = Base->watch([this](const std::vector<std::string> Changes) { |
| 241 | OnCommandChanged.broadcast(Changes); |
| 242 | }); |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 243 | } |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 244 | |
Ilya Biryukov | f2001aa | 2019-01-07 15:45:19 +0000 | [diff] [blame] | 245 | llvm::Optional<tooling::CompileCommand> |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 246 | OverlayCDB::getCompileCommand(PathRef File) const { |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 247 | llvm::Optional<tooling::CompileCommand> Cmd; |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 248 | { |
| 249 | std::lock_guard<std::mutex> Lock(Mutex); |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 250 | auto It = Commands.find(removeDots(File)); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 251 | if (It != Commands.end()) |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 252 | Cmd = It->second; |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 253 | } |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 254 | if (!Cmd && Base) |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 255 | Cmd = Base->getCompileCommand(File); |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 256 | if (!Cmd) |
| 257 | return llvm::None; |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame] | 258 | if (ArgsAdjuster) |
| 259 | Cmd->CommandLine = ArgsAdjuster(Cmd->CommandLine, Cmd->Filename); |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 260 | return Cmd; |
Alex Lorenz | f808786 | 2018-08-01 17:39:29 +0000 | [diff] [blame] | 261 | } |
| 262 | |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 263 | tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const { |
| 264 | auto Cmd = Base ? Base->getFallbackCommand(File) |
| 265 | : GlobalCompilationDatabase::getFallbackCommand(File); |
| 266 | std::lock_guard<std::mutex> Lock(Mutex); |
| 267 | Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(), |
| 268 | FallbackFlags.end()); |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame] | 269 | if (ArgsAdjuster) |
| 270 | Cmd.CommandLine = ArgsAdjuster(Cmd.CommandLine, Cmd.Filename); |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 271 | return Cmd; |
| 272 | } |
| 273 | |
| 274 | void OverlayCDB::setCompileCommand( |
| 275 | PathRef File, llvm::Optional<tooling::CompileCommand> Cmd) { |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 276 | // We store a canonical version internally to prevent mismatches between set |
| 277 | // and get compile commands. Also it assures clients listening to broadcasts |
| 278 | // doesn't receive different names for the same file. |
| 279 | std::string CanonPath = removeDots(File); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 280 | { |
| 281 | std::unique_lock<std::mutex> Lock(Mutex); |
| 282 | if (Cmd) |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 283 | Commands[CanonPath] = std::move(*Cmd); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 284 | else |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 285 | Commands.erase(CanonPath); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 286 | } |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 287 | OnCommandChanged.broadcast({CanonPath}); |
Alex Lorenz | f808786 | 2018-08-01 17:39:29 +0000 | [diff] [blame] | 288 | } |
| 289 | |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 290 | llvm::Optional<ProjectInfo> OverlayCDB::getProjectInfo(PathRef File) const { |
| 291 | { |
| 292 | std::lock_guard<std::mutex> Lock(Mutex); |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 293 | auto It = Commands.find(removeDots(File)); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 294 | if (It != Commands.end()) |
| 295 | return ProjectInfo{}; |
| 296 | } |
| 297 | if (Base) |
| 298 | return Base->getProjectInfo(File); |
| 299 | |
| 300 | return llvm::None; |
| 301 | } |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 302 | } // namespace clangd |
| 303 | } // namespace clang |