| 198 | llvm::cl::TokenizeWindowsCommandLineFull(command, saver, arguments); |
| 199 | #else |
| 200 | llvm::cl::TokenizeGNUCommandLine(command, saver, arguments); |
| 201 | #endif |
| 202 | |
| 203 | if(arguments.empty()) { |
| 204 | return {nullptr}; |
| 205 | } |
| 206 | |
| 207 | return save_compilation_info(file, directory, arguments); |
| 208 | } |
| 209 | |
| 210 | std::optional<std::size_t> CompilationDatabase::load(llvm::StringRef path) { |
| 211 | simdjson::padded_string json_buf; |
| 212 | if(auto error = simdjson::padded_string::load(std::string(path)).get(json_buf)) { |
| 213 | LOG_ERROR("Failed to read compilation database from {}: {}", |
| 214 | path, |
| 215 | simdjson::error_message(error)); |
| 216 | return std::nullopt; |
| 217 | } |
| 218 | |
| 219 | simdjson::ondemand::parser json_parser; |
| 220 | simdjson::ondemand::document doc; |
| 221 | if(auto error = json_parser.iterate(json_buf).get(doc)) { |
| 222 | LOG_ERROR("Failed to parse compilation database from {}: {}", |
| 223 | path, |
| 224 | simdjson::error_message(error)); |
| 225 | return std::nullopt; |
| 226 | } |
| 227 | |
| 228 | simdjson::ondemand::array arr; |
| 229 | if(auto error = doc.get_array().get(arr)) { |
| 230 | LOG_ERROR("Invalid compilation database format in {}: root element must be an array.", |
| 231 | path); |
| 232 | return std::nullopt; |
| 233 | } |
| 234 | |
| 235 | // Parse into a local vector and only swap it in at the end: a file that |
| 236 | // fails to read or parse at the top level leaves the loaded entries |
| 237 | // intact, so reload_and_diff() reports no change instead of dropping |
| 238 | // every file. A file truncated mid-array is NOT caught here (the |
| 239 | // entries before the cut still swap in) — the CDB poll's two-tick |
| 240 | // settle debounce is what keeps half-written files from being read. |
| 241 | std::vector<CompilationEntry> new_entries; |
| 242 | |
| 243 | std::size_t index = 0; |
| 244 | for(auto element: arr) { |
| 245 | simdjson::ondemand::object obj; |
| 246 | if(element.get_object().get(obj)) { |
| 247 | LOG_ERROR( |
| 248 | "Invalid compilation database in {}. Skipping item at index {}: " "item is not an object.", |
| 249 | path, |
| 250 | index); |
| 251 | ++index; |
| 252 | continue; |
| 253 | } |
| 254 | |
| 255 | std::string_view dir_sv, file_sv; |
| 256 | if(obj["directory"].get_string().get(dir_sv)) { |
| 257 | LOG_ERROR( |