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"); |
| 53 | Argv.push_back(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 |
| 98 | return Path; |
| 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; |
| 118 | std::string Error = ""; |
| 119 | Entry.CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error); |
| 120 | Entry.Path = Dir; |
| 121 | } |
| 122 | return R.first->second; |
Sam McCall | c02ba72 | 2017-12-22 09:47:34 +0000 | [diff] [blame] | 123 | } |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 124 | |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 125 | llvm::Optional<DirectoryBasedGlobalCompilationDatabase::CDBLookupResult> |
| 126 | DirectoryBasedGlobalCompilationDatabase::lookupCDB( |
| 127 | CDBLookupRequest Request) const { |
| 128 | assert(llvm::sys::path::is_absolute(Request.FileName) && |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 129 | "path must be absolute"); |
| 130 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 131 | bool ShouldBroadcast = false; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 132 | CDBLookupResult Result; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 133 | |
| 134 | { |
| 135 | std::lock_guard<std::mutex> Lock(Mutex); |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 136 | CachedCDB *Entry = nullptr; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 137 | if (CompileCommandsDir) { |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 138 | Entry = &getCDBInDirLocked(*CompileCommandsDir); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 139 | } else { |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 140 | // Traverse the canonical version to prevent false positives. i.e.: |
| 141 | // 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] | 142 | // FIXME(sammccall): this loop is hot, use a union-find-like structure. |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 143 | actOnAllParentDirectories(removeDots(Request.FileName), |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 144 | [&](PathRef Path) { |
| 145 | Entry = &getCDBInDirLocked(Path); |
| 146 | return Entry->CDB != nullptr; |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 147 | }); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 148 | } |
| 149 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 150 | if (!Entry || !Entry->CDB) |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 151 | return llvm::None; |
| 152 | |
| 153 | // Mark CDB as broadcasted to make sure discovery is performed once. |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 154 | if (Request.ShouldBroadcast && !Entry->SentBroadcast) { |
| 155 | Entry->SentBroadcast = true; |
| 156 | ShouldBroadcast = true; |
| 157 | } |
| 158 | |
| 159 | Result.CDB = Entry->CDB.get(); |
| 160 | Result.PI.SourceRoot = Entry->Path; |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | // FIXME: Maybe make the following part async, since this can block retrieval |
| 164 | // of compile commands. |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 165 | if (ShouldBroadcast) |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 166 | broadcastCDB(Result); |
| 167 | return Result; |
| 168 | } |
| 169 | |
| 170 | void DirectoryBasedGlobalCompilationDatabase::broadcastCDB( |
| 171 | CDBLookupResult Result) const { |
| 172 | assert(Result.CDB && "Trying to broadcast an invalid CDB!"); |
| 173 | |
| 174 | std::vector<std::string> AllFiles = Result.CDB->getAllFiles(); |
| 175 | // We assume CDB in CompileCommandsDir owns all of its entries, since we don't |
| 176 | // perform any search in parent paths whenever it is set. |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 177 | if (CompileCommandsDir) { |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 178 | assert(*CompileCommandsDir == Result.PI.SourceRoot && |
| 179 | "Trying to broadcast a CDB outside of CompileCommandsDir!"); |
| 180 | OnCommandChanged.broadcast(std::move(AllFiles)); |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | llvm::StringMap<bool> DirectoryHasCDB; |
| 185 | { |
| 186 | std::lock_guard<std::mutex> Lock(Mutex); |
| 187 | // Uniquify all parent directories of all files. |
| 188 | for (llvm::StringRef File : AllFiles) { |
| 189 | actOnAllParentDirectories(File, [&](PathRef Path) { |
| 190 | auto It = DirectoryHasCDB.try_emplace(Path); |
| 191 | // Already seen this path, and all of its parents. |
| 192 | if (!It.second) |
| 193 | return true; |
| 194 | |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 195 | CachedCDB &Entry = getCDBInDirLocked(Path); |
| 196 | It.first->second = Entry.CDB != nullptr; |
| 197 | return pathEqual(Path, Result.PI.SourceRoot); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 198 | }); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 199 | } |
| 200 | } |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 201 | |
| 202 | std::vector<std::string> GovernedFiles; |
| 203 | for (llvm::StringRef File : AllFiles) { |
| 204 | // A file is governed by this CDB if lookup for the file would find it. |
| 205 | // Independent of whether it has an entry for that file or not. |
| 206 | actOnAllParentDirectories(File, [&](PathRef Path) { |
| 207 | if (DirectoryHasCDB.lookup(Path)) { |
Sam McCall | 7ee0867 | 2019-07-26 14:07:11 +0000 | [diff] [blame] | 208 | if (pathEqual(Path, Result.PI.SourceRoot)) |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 209 | // Make sure listeners always get a canonical path for the file. |
| 210 | GovernedFiles.push_back(removeDots(File)); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 211 | // Stop as soon as we hit a CDB. |
| 212 | return true; |
| 213 | } |
| 214 | return false; |
| 215 | }); |
| 216 | } |
| 217 | |
| 218 | OnCommandChanged.broadcast(std::move(GovernedFiles)); |
| 219 | } |
| 220 | |
| 221 | llvm::Optional<ProjectInfo> |
| 222 | DirectoryBasedGlobalCompilationDatabase::getProjectInfo(PathRef File) const { |
| 223 | CDBLookupRequest Req; |
| 224 | Req.FileName = File; |
| 225 | Req.ShouldBroadcast = false; |
| 226 | auto Res = lookupCDB(Req); |
| 227 | if (!Res) |
| 228 | return llvm::None; |
| 229 | return Res->PI; |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base, |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 233 | std::vector<std::string> FallbackFlags, |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame^] | 234 | tooling::ArgumentsAdjuster Adjuster) |
| 235 | : Base(Base), ArgsAdjuster(std::move(Adjuster)), |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 236 | FallbackFlags(std::move(FallbackFlags)) { |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 237 | if (Base) |
| 238 | BaseChanged = Base->watch([this](const std::vector<std::string> Changes) { |
| 239 | OnCommandChanged.broadcast(Changes); |
| 240 | }); |
Ilya Biryukov | 38d7977 | 2017-05-16 09:38:59 +0000 | [diff] [blame] | 241 | } |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 242 | |
Ilya Biryukov | f2001aa | 2019-01-07 15:45:19 +0000 | [diff] [blame] | 243 | llvm::Optional<tooling::CompileCommand> |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 244 | OverlayCDB::getCompileCommand(PathRef File) const { |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 245 | llvm::Optional<tooling::CompileCommand> Cmd; |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 246 | { |
| 247 | std::lock_guard<std::mutex> Lock(Mutex); |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 248 | auto It = Commands.find(removeDots(File)); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 249 | if (It != Commands.end()) |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 250 | Cmd = It->second; |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 251 | } |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 252 | if (!Cmd && Base) |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 253 | Cmd = Base->getCompileCommand(File); |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 254 | if (!Cmd) |
| 255 | return llvm::None; |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame^] | 256 | if (ArgsAdjuster) |
| 257 | Cmd->CommandLine = ArgsAdjuster(Cmd->CommandLine, Cmd->Filename); |
Kadir Cetinkaya | be6b35d | 2019-01-22 09:10:20 +0000 | [diff] [blame] | 258 | return Cmd; |
Alex Lorenz | f808786 | 2018-08-01 17:39:29 +0000 | [diff] [blame] | 259 | } |
| 260 | |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 261 | tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const { |
| 262 | auto Cmd = Base ? Base->getFallbackCommand(File) |
| 263 | : GlobalCompilationDatabase::getFallbackCommand(File); |
| 264 | std::lock_guard<std::mutex> Lock(Mutex); |
| 265 | Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(), |
| 266 | FallbackFlags.end()); |
Sam McCall | 99768b2 | 2019-11-29 19:37:48 +0100 | [diff] [blame^] | 267 | if (ArgsAdjuster) |
| 268 | Cmd.CommandLine = ArgsAdjuster(Cmd.CommandLine, Cmd.Filename); |
Sam McCall | c55d09a | 2018-11-02 13:09:36 +0000 | [diff] [blame] | 269 | return Cmd; |
| 270 | } |
| 271 | |
| 272 | void OverlayCDB::setCompileCommand( |
| 273 | PathRef File, llvm::Optional<tooling::CompileCommand> Cmd) { |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 274 | // We store a canonical version internally to prevent mismatches between set |
| 275 | // and get compile commands. Also it assures clients listening to broadcasts |
| 276 | // doesn't receive different names for the same file. |
| 277 | std::string CanonPath = removeDots(File); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 278 | { |
| 279 | std::unique_lock<std::mutex> Lock(Mutex); |
| 280 | if (Cmd) |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 281 | Commands[CanonPath] = std::move(*Cmd); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 282 | else |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 283 | Commands.erase(CanonPath); |
Sam McCall | 2bebc3d | 2018-11-20 10:56:03 +0000 | [diff] [blame] | 284 | } |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 285 | OnCommandChanged.broadcast({CanonPath}); |
Alex Lorenz | f808786 | 2018-08-01 17:39:29 +0000 | [diff] [blame] | 286 | } |
| 287 | |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 288 | llvm::Optional<ProjectInfo> OverlayCDB::getProjectInfo(PathRef File) const { |
| 289 | { |
| 290 | std::lock_guard<std::mutex> Lock(Mutex); |
Kadir Cetinkaya | 6d53adf | 2019-07-18 16:13:23 +0000 | [diff] [blame] | 291 | auto It = Commands.find(removeDots(File)); |
Kadir Cetinkaya | ad54935 | 2019-07-11 09:54:31 +0000 | [diff] [blame] | 292 | if (It != Commands.end()) |
| 293 | return ProjectInfo{}; |
| 294 | } |
| 295 | if (Base) |
| 296 | return Base->getProjectInfo(File); |
| 297 | |
| 298 | return llvm::None; |
| 299 | } |
Krasimir Georgiev | c2a16a3 | 2017-07-06 08:44:54 +0000 | [diff] [blame] | 300 | } // namespace clangd |
| 301 | } // namespace clang |