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