1 //===--- ClangdMain.cpp - clangd server loop ------------------------------===// 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 "ClangdMain.h" 10 #include "ClangdLSPServer.h" 11 #include "CodeComplete.h" 12 #include "Compiler.h" 13 #include "Config.h" 14 #include "ConfigProvider.h" 15 #include "Feature.h" 16 #include "IncludeCleaner.h" 17 #include "PathMapping.h" 18 #include "Protocol.h" 19 #include "TidyProvider.h" 20 #include "Transport.h" 21 #include "index/Background.h" 22 #include "index/Index.h" 23 #include "index/MemIndex.h" 24 #include "index/Merge.h" 25 #include "index/ProjectAware.h" 26 #include "index/remote/Client.h" 27 #include "support/Path.h" 28 #include "support/Shutdown.h" 29 #include "support/ThreadCrashReporter.h" 30 #include "support/ThreadsafeFS.h" 31 #include "support/Trace.h" 32 #include "clang/Basic/Stack.h" 33 #include "clang/Format/Format.h" 34 #include "llvm/ADT/SmallString.h" 35 #include "llvm/ADT/StringRef.h" 36 #include "llvm/Support/CommandLine.h" 37 #include "llvm/Support/FileSystem.h" 38 #include "llvm/Support/InitLLVM.h" 39 #include "llvm/Support/Path.h" 40 #include "llvm/Support/Process.h" 41 #include "llvm/Support/Program.h" 42 #include "llvm/Support/Signals.h" 43 #include "llvm/Support/TargetSelect.h" 44 #include "llvm/Support/raw_ostream.h" 45 #include <chrono> 46 #include <cstdlib> 47 #include <memory> 48 #include <mutex> 49 #include <optional> 50 #include <string> 51 #include <thread> 52 #include <utility> 53 #include <vector> 54 55 #ifndef _WIN32 56 #include <unistd.h> 57 #endif 58 59 #ifdef __GLIBC__ 60 #include <malloc.h> 61 #endif 62 63 namespace clang { 64 namespace clangd { 65 66 // Implemented in Check.cpp. 67 bool check(const llvm::StringRef File, const ThreadsafeFS &TFS, 68 const ClangdLSPServer::Options &Opts); 69 70 namespace { 71 72 using llvm::cl::cat; 73 using llvm::cl::CommaSeparated; 74 using llvm::cl::desc; 75 using llvm::cl::Hidden; 76 using llvm::cl::init; 77 using llvm::cl::list; 78 using llvm::cl::opt; 79 using llvm::cl::OptionCategory; 80 using llvm::cl::ValueOptional; 81 using llvm::cl::values; 82 83 // All flags must be placed in a category, or they will be shown neither in 84 // --help, nor --help-hidden! 85 OptionCategory CompileCommands("clangd compilation flags options"); 86 OptionCategory Features("clangd feature options"); 87 OptionCategory Misc("clangd miscellaneous options"); 88 OptionCategory Protocol("clangd protocol and logging options"); 89 OptionCategory Retired("clangd flags no longer in use"); 90 const OptionCategory *ClangdCategories[] = {&Features, &Protocol, 91 &CompileCommands, &Misc, &Retired}; 92 93 template <typename T> class RetiredFlag { 94 opt<T> Option; 95 96 public: 97 RetiredFlag(llvm::StringRef Name) 98 : Option(Name, cat(Retired), desc("Obsolete flag, ignored"), Hidden, 99 llvm::cl::callback([Name](const T &) { 100 llvm::errs() 101 << "The flag `-" << Name << "` is obsolete and ignored.\n"; 102 })) {} 103 }; 104 105 enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs }; 106 opt<CompileArgsFrom> CompileArgsFrom{ 107 "compile_args_from", 108 cat(CompileCommands), 109 desc("The source of compile commands"), 110 values(clEnumValN(LSPCompileArgs, "lsp", 111 "All compile commands come from LSP and " 112 "'compile_commands.json' files are ignored"), 113 clEnumValN(FilesystemCompileArgs, "filesystem", 114 "All compile commands come from the " 115 "'compile_commands.json' files")), 116 init(FilesystemCompileArgs), 117 Hidden, 118 }; 119 120 opt<Path> CompileCommandsDir{ 121 "compile-commands-dir", 122 cat(CompileCommands), 123 desc("Specify a path to look for compile_commands.json. If path " 124 "is invalid, clangd will look in the current directory and " 125 "parent paths of each source file"), 126 }; 127 128 opt<Path> ResourceDir{ 129 "resource-dir", 130 cat(CompileCommands), 131 desc("Directory for system clang headers"), 132 init(""), 133 Hidden, 134 }; 135 136 list<std::string> QueryDriverGlobs{ 137 "query-driver", 138 cat(CompileCommands), 139 desc( 140 "Comma separated list of globs for white-listing gcc-compatible " 141 "drivers that are safe to execute. Drivers matching any of these globs " 142 "will be used to extract system includes. e.g. " 143 "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"), 144 CommaSeparated, 145 }; 146 147 // FIXME: Flags are the wrong mechanism for user preferences. 148 // We should probably read a dotfile or similar. 149 opt<bool> AllScopesCompletion{ 150 "all-scopes-completion", 151 cat(Features), 152 desc("If set to true, code completion will include index symbols that are " 153 "not defined in the scopes (e.g. " 154 "namespaces) visible from the code completion point. Such completions " 155 "can insert scope qualifiers"), 156 init(true), 157 }; 158 159 opt<bool> ShowOrigins{ 160 "debug-origin", 161 cat(Features), 162 desc("Show origins of completion items"), 163 init(CodeCompleteOptions().ShowOrigins), 164 Hidden, 165 }; 166 167 opt<bool> EnableBackgroundIndex{ 168 "background-index", 169 cat(Features), 170 desc("Index project code in the background and persist index on disk."), 171 init(true), 172 }; 173 174 opt<llvm::ThreadPriority> BackgroundIndexPriority{ 175 "background-index-priority", 176 cat(Features), 177 desc("Thread priority for building the background index. " 178 "The effect of this flag is OS-specific."), 179 values(clEnumValN(llvm::ThreadPriority::Background, "background", 180 "Minimum priority, runs on idle CPUs. " 181 "May leave 'performance' cores unused."), 182 clEnumValN(llvm::ThreadPriority::Low, "low", 183 "Reduced priority compared to interactive work."), 184 clEnumValN(llvm::ThreadPriority::Default, "normal", 185 "Same priority as other clangd work.")), 186 init(llvm::ThreadPriority::Low), 187 }; 188 189 opt<bool> EnableClangTidy{ 190 "clang-tidy", 191 cat(Features), 192 desc("Enable clang-tidy diagnostics"), 193 init(true), 194 }; 195 196 opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{ 197 "completion-parse", 198 cat(Features), 199 desc("Whether the clang-parser is used for code-completion"), 200 values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always", 201 "Block until the parser can be used"), 202 clEnumValN(CodeCompleteOptions::ParseIfReady, "auto", 203 "Use text-based completion if the parser " 204 "is not ready"), 205 clEnumValN(CodeCompleteOptions::NeverParse, "never", 206 "Always used text-based completion")), 207 init(CodeCompleteOptions().RunParser), 208 Hidden, 209 }; 210 211 opt<CodeCompleteOptions::CodeCompletionRankingModel> RankingModel{ 212 "ranking-model", 213 cat(Features), 214 desc("Model to use to rank code-completion items"), 215 values(clEnumValN(CodeCompleteOptions::Heuristics, "heuristics", 216 "Use heuristics to rank code completion items"), 217 clEnumValN(CodeCompleteOptions::DecisionForest, "decision_forest", 218 "Use Decision Forest model to rank completion items")), 219 init(CodeCompleteOptions().RankingModel), 220 Hidden, 221 }; 222 223 // FIXME: also support "plain" style where signatures are always omitted. 224 enum CompletionStyleFlag { Detailed, Bundled }; 225 opt<CompletionStyleFlag> CompletionStyle{ 226 "completion-style", 227 cat(Features), 228 desc("Granularity of code completion suggestions"), 229 values(clEnumValN(Detailed, "detailed", 230 "One completion item for each semantically distinct " 231 "completion, with full type information"), 232 clEnumValN(Bundled, "bundled", 233 "Similar completion items (e.g. function overloads) are " 234 "combined. Type information shown where possible")), 235 }; 236 237 opt<std::string> FallbackStyle{ 238 "fallback-style", 239 cat(Features), 240 desc("clang-format style to apply by default when " 241 "no .clang-format file is found"), 242 init(clang::format::DefaultFallbackStyle), 243 }; 244 245 opt<std::string> EnableFunctionArgSnippets{ 246 "function-arg-placeholders", 247 cat(Features), 248 desc("When disabled (0), completions contain only parentheses for " 249 "function calls. When enabled (1), completions also contain " 250 "placeholders for method parameters"), 251 init("-1"), 252 }; 253 254 opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{ 255 "header-insertion", 256 cat(Features), 257 desc("Add #include directives when accepting code completions"), 258 init(CodeCompleteOptions().InsertIncludes), 259 values( 260 clEnumValN(CodeCompleteOptions::IWYU, "iwyu", 261 "Include what you use. " 262 "Insert the owning header for top-level symbols, unless the " 263 "header is already directly included or the symbol is " 264 "forward-declared"), 265 clEnumValN( 266 CodeCompleteOptions::NeverInsert, "never", 267 "Never insert #include directives as part of code completion")), 268 }; 269 270 opt<bool> ImportInsertions{ 271 "import-insertions", 272 cat(Features), 273 desc("If header insertion is enabled, add #import directives when " 274 "accepting code completions or fixing includes in Objective-C code"), 275 init(CodeCompleteOptions().ImportInsertions), 276 }; 277 278 opt<bool> HeaderInsertionDecorators{ 279 "header-insertion-decorators", 280 cat(Features), 281 desc("Prepend a circular dot or space before the completion " 282 "label, depending on whether " 283 "an include line will be inserted or not"), 284 init(true), 285 }; 286 287 opt<bool> HiddenFeatures{ 288 "hidden-features", 289 cat(Features), 290 desc("Enable hidden features mostly useful to clangd developers"), 291 init(false), 292 Hidden, 293 }; 294 295 opt<bool> IncludeIneligibleResults{ 296 "include-ineligible-results", 297 cat(Features), 298 desc("Include ineligible completion results (e.g. private members)"), 299 init(CodeCompleteOptions().IncludeIneligibleResults), 300 Hidden, 301 }; 302 303 RetiredFlag<bool> EnableIndex("index"); 304 RetiredFlag<bool> SuggestMissingIncludes("suggest-missing-includes"); 305 RetiredFlag<bool> RecoveryAST("recovery-ast"); 306 RetiredFlag<bool> RecoveryASTType("recovery-ast-type"); 307 RetiredFlag<bool> AsyncPreamble("async-preamble"); 308 RetiredFlag<bool> CollectMainFileRefs("collect-main-file-refs"); 309 RetiredFlag<bool> CrossFileRename("cross-file-rename"); 310 RetiredFlag<std::string> ClangTidyChecks("clang-tidy-checks"); 311 RetiredFlag<bool> InlayHints("inlay-hints"); 312 RetiredFlag<bool> FoldingRanges("folding-ranges"); 313 RetiredFlag<bool> IncludeCleanerStdlib("include-cleaner-stdlib"); 314 315 opt<int> LimitResults{ 316 "limit-results", 317 cat(Features), 318 desc("Limit the number of results returned by clangd. " 319 "0 means no limit (default=100)"), 320 init(100), 321 }; 322 323 opt<int> ReferencesLimit{ 324 "limit-references", 325 cat(Features), 326 desc("Limit the number of references returned by clangd. " 327 "0 means no limit (default=1000)"), 328 init(1000), 329 }; 330 331 opt<int> RenameFileLimit{ 332 "rename-file-limit", 333 cat(Features), 334 desc("Limit the number of files to be affected by symbol renaming. " 335 "0 means no limit (default=50)"), 336 init(50), 337 }; 338 339 list<std::string> TweakList{ 340 "tweaks", 341 cat(Features), 342 desc("Specify a list of Tweaks to enable (only for clangd developers)."), 343 Hidden, 344 CommaSeparated, 345 }; 346 347 opt<unsigned> WorkerThreadsCount{ 348 "j", 349 cat(Misc), 350 desc("Number of async workers used by clangd. Background index also " 351 "uses this many workers."), 352 init(getDefaultAsyncThreadsCount()), 353 }; 354 355 opt<Path> IndexFile{ 356 "index-file", 357 cat(Misc), 358 desc( 359 "Index file to build the static index. The file must have been created " 360 "by a compatible clangd-indexer\n" 361 "WARNING: This option is experimental only, and will be removed " 362 "eventually. Don't rely on it"), 363 init(""), 364 Hidden, 365 }; 366 367 opt<bool> Test{ 368 "lit-test", 369 cat(Misc), 370 desc("Abbreviation for -input-style=delimited -pretty -sync " 371 "-enable-test-scheme -enable-config=0 -log=verbose -crash-pragmas. " 372 "Also sets config options: Index.StandardLibrary=false. " 373 "Intended to simplify lit tests"), 374 init(false), 375 Hidden, 376 }; 377 378 opt<bool> CrashPragmas{ 379 "crash-pragmas", 380 cat(Misc), 381 desc("Respect `#pragma clang __debug crash` and friends."), 382 init(false), 383 Hidden, 384 }; 385 386 opt<Path> CheckFile{ 387 "check", 388 cat(Misc), 389 desc("Parse one file in isolation instead of acting as a language server. " 390 "Useful to investigate/reproduce crashes or configuration problems. " 391 "With --check=<filename>, attempts to parse a particular file."), 392 init(""), 393 ValueOptional, 394 }; 395 396 enum PCHStorageFlag { Disk, Memory }; 397 opt<PCHStorageFlag> PCHStorage{ 398 "pch-storage", 399 cat(Misc), 400 desc("Storing PCHs in memory increases memory usages, but may " 401 "improve performance"), 402 values( 403 clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"), 404 clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")), 405 init(PCHStorageFlag::Disk), 406 }; 407 408 opt<bool> Sync{ 409 "sync", 410 cat(Misc), 411 desc("Handle client requests on main thread. Background index still uses " 412 "its own thread."), 413 init(false), 414 Hidden, 415 }; 416 417 opt<JSONStreamStyle> InputStyle{ 418 "input-style", 419 cat(Protocol), 420 desc("Input JSON stream encoding"), 421 values( 422 clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"), 423 clEnumValN(JSONStreamStyle::Delimited, "delimited", 424 "messages delimited by --- lines, with # comment support")), 425 init(JSONStreamStyle::Standard), 426 Hidden, 427 }; 428 429 opt<bool> EnableTestScheme{ 430 "enable-test-uri-scheme", 431 cat(Protocol), 432 desc("Enable 'test:' URI scheme. Only use in lit tests"), 433 init(false), 434 Hidden, 435 }; 436 437 opt<std::string> PathMappingsArg{ 438 "path-mappings", 439 cat(Protocol), 440 desc( 441 "Translates between client paths (as seen by a remote editor) and " 442 "server paths (where clangd sees files on disk). " 443 "Comma separated list of '<client_path>=<server_path>' pairs, the " 444 "first entry matching a given path is used. " 445 "e.g. /home/project/incl=/opt/include,/home/project=/workarea/project"), 446 init(""), 447 }; 448 449 opt<Path> InputMirrorFile{ 450 "input-mirror-file", 451 cat(Protocol), 452 desc("Mirror all LSP input to the specified file. Useful for debugging"), 453 init(""), 454 Hidden, 455 }; 456 457 opt<Logger::Level> LogLevel{ 458 "log", 459 cat(Protocol), 460 desc("Verbosity of log messages written to stderr"), 461 values(clEnumValN(Logger::Error, "error", "Error messages only"), 462 clEnumValN(Logger::Info, "info", "High level execution tracing"), 463 clEnumValN(Logger::Debug, "verbose", "Low level details")), 464 init(Logger::Info), 465 }; 466 467 opt<OffsetEncoding> ForceOffsetEncoding{ 468 "offset-encoding", 469 cat(Protocol), 470 desc("Force the offsetEncoding used for character positions. " 471 "This bypasses negotiation via client capabilities"), 472 values( 473 clEnumValN(OffsetEncoding::UTF8, "utf-8", "Offsets are in UTF-8 bytes"), 474 clEnumValN(OffsetEncoding::UTF16, "utf-16", 475 "Offsets are in UTF-16 code units"), 476 clEnumValN(OffsetEncoding::UTF32, "utf-32", 477 "Offsets are in unicode codepoints")), 478 init(OffsetEncoding::UnsupportedEncoding), 479 }; 480 481 opt<bool> PrettyPrint{ 482 "pretty", 483 cat(Protocol), 484 desc("Pretty-print JSON output"), 485 init(false), 486 }; 487 488 opt<bool> EnableConfig{ 489 "enable-config", 490 cat(Misc), 491 desc( 492 "Read user and project configuration from YAML files.\n" 493 "Project config is from a .clangd file in the project directory.\n" 494 "User config is from clangd/config.yaml in the following directories:\n" 495 "\tWindows: %USERPROFILE%\\AppData\\Local\n" 496 "\tMac OS: ~/Library/Preferences/\n" 497 "\tOthers: $XDG_CONFIG_HOME, usually ~/.config\n" 498 "Configuration is documented at https://clangd.llvm.org/config.html"), 499 init(true), 500 }; 501 502 opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc), 503 desc("Use files open in the editor when parsing " 504 "headers instead of reading from the disk"), 505 Hidden, 506 init(ClangdServer::Options().UseDirtyHeaders)}; 507 508 opt<bool> PreambleParseForwardingFunctions{ 509 "parse-forwarding-functions", 510 cat(Misc), 511 desc("Parse all emplace-like functions in included headers"), 512 Hidden, 513 init(ParseOptions().PreambleParseForwardingFunctions), 514 }; 515 516 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM 517 opt<bool> EnableMallocTrim{ 518 "malloc-trim", 519 cat(Misc), 520 desc("Release memory periodically via malloc_trim(3)."), 521 init(true), 522 }; 523 524 std::function<void()> getMemoryCleanupFunction() { 525 if (!EnableMallocTrim) 526 return nullptr; 527 // Leave a few MB at the top of the heap: it is insignificant 528 // and will most likely be needed by the main thread 529 constexpr size_t MallocTrimPad = 20'000'000; 530 return []() { 531 if (malloc_trim(MallocTrimPad)) 532 vlog("Released memory via malloc_trim"); 533 }; 534 } 535 #else 536 std::function<void()> getMemoryCleanupFunction() { return nullptr; } 537 #endif 538 539 #if CLANGD_ENABLE_REMOTE 540 opt<std::string> RemoteIndexAddress{ 541 "remote-index-address", 542 cat(Features), 543 desc("Address of the remote index server"), 544 }; 545 546 // FIXME(kirillbobyrev): Should this be the location of compile_commands.json? 547 opt<std::string> ProjectRoot{ 548 "project-root", 549 cat(Features), 550 desc("Path to the project root. Requires remote-index-address to be set."), 551 }; 552 #endif 553 554 opt<bool> ExperimentalModulesSupport{ 555 "experimental-modules-support", 556 cat(Features), 557 desc("Experimental support for standard c++ modules"), 558 init(false), 559 }; 560 561 /// Supports a test URI scheme with relaxed constraints for lit tests. 562 /// The path in a test URI will be combined with a platform-specific fake 563 /// directory to form an absolute path. For example, test:///a.cpp is resolved 564 /// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix. 565 class TestScheme : public URIScheme { 566 public: 567 llvm::Expected<std::string> 568 getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body, 569 llvm::StringRef /*HintPath*/) const override { 570 using namespace llvm::sys; 571 // Still require "/" in body to mimic file scheme, as we want lengths of an 572 // equivalent URI in both schemes to be the same. 573 if (!Body.starts_with("/")) 574 return error( 575 "Expect URI body to be an absolute path starting with '/': {0}", 576 Body); 577 Body = Body.ltrim('/'); 578 llvm::SmallString<16> Path(Body); 579 path::native(Path); 580 fs::make_absolute(TestScheme::TestDir, Path); 581 return std::string(Path); 582 } 583 584 llvm::Expected<URI> 585 uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override { 586 llvm::StringRef Body = AbsolutePath; 587 if (!Body.consume_front(TestScheme::TestDir)) 588 return error("Path {0} doesn't start with root {1}", AbsolutePath, 589 TestDir); 590 591 return URI("test", /*Authority=*/"", 592 llvm::sys::path::convert_to_slash(Body)); 593 } 594 595 private: 596 const static char TestDir[]; 597 }; 598 599 #ifdef _WIN32 600 const char TestScheme::TestDir[] = "C:\\clangd-test"; 601 #else 602 const char TestScheme::TestDir[] = "/clangd-test"; 603 #endif 604 605 std::unique_ptr<SymbolIndex> 606 loadExternalIndex(const Config::ExternalIndexSpec &External, 607 AsyncTaskRunner *Tasks, bool SupportContainedRefs) { 608 static const trace::Metric RemoteIndexUsed("used_remote_index", 609 trace::Metric::Value, "address"); 610 switch (External.Kind) { 611 case Config::ExternalIndexSpec::None: 612 break; 613 case Config::ExternalIndexSpec::Server: 614 RemoteIndexUsed.record(1, External.Location); 615 log("Associating {0} with remote index at {1}.", External.MountPoint, 616 External.Location); 617 return remote::getClient(External.Location, External.MountPoint); 618 case Config::ExternalIndexSpec::File: 619 log("Associating {0} with monolithic index at {1}.", External.MountPoint, 620 External.Location); 621 auto NewIndex = std::make_unique<SwapIndex>(std::make_unique<MemIndex>()); 622 auto IndexLoadTask = [File = External.Location, 623 PlaceHolder = NewIndex.get(), SupportContainedRefs] { 624 if (auto Idx = loadIndex(File, SymbolOrigin::Static, /*UseDex=*/true, 625 SupportContainedRefs)) 626 PlaceHolder->reset(std::move(Idx)); 627 }; 628 if (Tasks) { 629 Tasks->runAsync("Load-index:" + External.Location, 630 std::move(IndexLoadTask)); 631 } else { 632 IndexLoadTask(); 633 } 634 return std::move(NewIndex); 635 } 636 llvm_unreachable("Invalid ExternalIndexKind."); 637 } 638 639 std::optional<bool> shouldEnableFunctionArgSnippets() { 640 std::string Val = EnableFunctionArgSnippets; 641 // Accept the same values that a bool option parser would, but also accept 642 // -1 to indicate "unspecified", in which case the ArgumentListsPolicy 643 // config option will be respected. 644 if (Val == "1" || Val == "true" || Val == "True" || Val == "TRUE") 645 return true; 646 if (Val == "0" || Val == "false" || Val == "False" || Val == "FALSE") 647 return false; 648 if (Val != "-1") 649 elog("Value specified by --function-arg-placeholders is invalid. Provide a " 650 "boolean value or leave unspecified to use ArgumentListsPolicy from " 651 "config instead."); 652 return std::nullopt; 653 } 654 655 class FlagsConfigProvider : public config::Provider { 656 private: 657 config::CompiledFragment Frag; 658 659 std::vector<config::CompiledFragment> 660 getFragments(const config::Params &, 661 config::DiagnosticCallback) const override { 662 return {Frag}; 663 } 664 665 public: 666 FlagsConfigProvider() { 667 std::optional<Config::CDBSearchSpec> CDBSearch; 668 std::optional<Config::ExternalIndexSpec> IndexSpec; 669 std::optional<Config::BackgroundPolicy> BGPolicy; 670 std::optional<Config::ArgumentListsPolicy> ArgumentLists; 671 672 // If --compile-commands-dir arg was invoked, check value and override 673 // default path. 674 if (!CompileCommandsDir.empty()) { 675 if (llvm::sys::fs::exists(CompileCommandsDir)) { 676 // We support passing both relative and absolute paths to the 677 // --compile-commands-dir argument, but we assume the path is absolute 678 // in the rest of clangd so we make sure the path is absolute before 679 // continuing. 680 llvm::SmallString<128> Path(CompileCommandsDir); 681 if (std::error_code EC = llvm::sys::fs::make_absolute(Path)) { 682 elog("Error while converting the relative path specified by " 683 "--compile-commands-dir to an absolute path: {0}. The argument " 684 "will be ignored.", 685 EC.message()); 686 } else { 687 CDBSearch = {Config::CDBSearchSpec::FixedDir, Path.str().str()}; 688 } 689 } else { 690 elog("Path specified by --compile-commands-dir does not exist. The " 691 "argument will be ignored."); 692 } 693 } 694 if (!IndexFile.empty()) { 695 Config::ExternalIndexSpec Spec; 696 Spec.Kind = Spec.File; 697 Spec.Location = IndexFile; 698 IndexSpec = std::move(Spec); 699 } 700 #if CLANGD_ENABLE_REMOTE 701 if (!RemoteIndexAddress.empty()) { 702 assert(!ProjectRoot.empty() && IndexFile.empty()); 703 Config::ExternalIndexSpec Spec; 704 Spec.Kind = Spec.Server; 705 Spec.Location = RemoteIndexAddress; 706 Spec.MountPoint = ProjectRoot; 707 IndexSpec = std::move(Spec); 708 BGPolicy = Config::BackgroundPolicy::Skip; 709 } 710 #endif 711 if (!EnableBackgroundIndex) { 712 BGPolicy = Config::BackgroundPolicy::Skip; 713 } 714 715 if (std::optional<bool> Enable = shouldEnableFunctionArgSnippets()) { 716 ArgumentLists = *Enable ? Config::ArgumentListsPolicy::FullPlaceholders 717 : Config::ArgumentListsPolicy::Delimiters; 718 } 719 720 Frag = [=](const config::Params &, Config &C) { 721 if (CDBSearch) 722 C.CompileFlags.CDBSearch = *CDBSearch; 723 if (IndexSpec) 724 C.Index.External = *IndexSpec; 725 if (BGPolicy) 726 C.Index.Background = *BGPolicy; 727 if (ArgumentLists) 728 C.Completion.ArgumentLists = *ArgumentLists; 729 if (AllScopesCompletion.getNumOccurrences()) 730 C.Completion.AllScopes = AllScopesCompletion; 731 732 if (Test) 733 C.Index.StandardLibrary = false; 734 return true; 735 }; 736 } 737 }; 738 } // namespace 739 740 enum class ErrorResultCode : int { 741 NoShutdownRequest = 1, 742 CantRunAsXPCService = 2, 743 CheckFailed = 3 744 }; 745 746 int clangdMain(int argc, char *argv[]) { 747 // Clang could run on the main thread. e.g., when the flag '-check' or '-sync' 748 // is enabled. 749 clang::noteBottomOfStack(); 750 llvm::InitLLVM X(argc, argv); 751 llvm::InitializeAllTargetInfos(); 752 llvm::sys::AddSignalHandler( 753 [](void *) { 754 ThreadCrashReporter::runCrashHandlers(); 755 // Ensure ThreadCrashReporter and PrintStackTrace output is visible. 756 llvm::errs().flush(); 757 }, 758 nullptr); 759 llvm::sys::SetInterruptFunction(&requestShutdown); 760 llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { 761 OS << versionString() << "\n" 762 << "Features: " << featureString() << "\n" 763 << "Platform: " << platformString() << "\n"; 764 }); 765 const char *FlagsEnvVar = "CLANGD_FLAGS"; 766 const char *Overview = 767 R"(clangd is a language server that provides IDE-like features to editors. 768 769 It should be used via an editor plugin rather than invoked directly. For more information, see: 770 https://clangd.llvm.org/ 771 https://microsoft.github.io/language-server-protocol/ 772 773 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. 774 )"; 775 llvm::cl::HideUnrelatedOptions(ClangdCategories); 776 llvm::cl::ParseCommandLineOptions(argc, argv, Overview, 777 /*Errs=*/nullptr, FlagsEnvVar); 778 if (Test) { 779 if (!Sync.getNumOccurrences()) 780 Sync = true; 781 if (!CrashPragmas.getNumOccurrences()) 782 CrashPragmas = true; 783 InputStyle = JSONStreamStyle::Delimited; 784 LogLevel = Logger::Verbose; 785 PrettyPrint = true; 786 // Disable config system by default to avoid external reads. 787 if (!EnableConfig.getNumOccurrences()) 788 EnableConfig = false; 789 // Disable background index on lit tests by default to prevent disk writes. 790 if (!EnableBackgroundIndex.getNumOccurrences()) 791 EnableBackgroundIndex = false; 792 // Ensure background index makes progress. 793 else if (EnableBackgroundIndex) 794 BackgroundQueue::preventThreadStarvationInTests(); 795 } 796 if (Test || EnableTestScheme) { 797 static URISchemeRegistry::Add<TestScheme> X( 798 "test", "Test scheme for clangd lit tests."); 799 } 800 if (CrashPragmas) 801 allowCrashPragmasForTest(); 802 803 if (!Sync && WorkerThreadsCount == 0) { 804 llvm::errs() << "A number of worker threads cannot be 0. Did you mean to " 805 "specify -sync?"; 806 return 1; 807 } 808 809 if (Sync) { 810 if (WorkerThreadsCount.getNumOccurrences()) 811 llvm::errs() << "Ignoring -j because -sync is set.\n"; 812 WorkerThreadsCount = 0; 813 } 814 if (FallbackStyle.getNumOccurrences()) 815 clang::format::DefaultFallbackStyle = FallbackStyle.c_str(); 816 817 // Validate command line arguments. 818 std::optional<llvm::raw_fd_ostream> InputMirrorStream; 819 if (!InputMirrorFile.empty()) { 820 std::error_code EC; 821 InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC, 822 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write); 823 if (EC) { 824 InputMirrorStream.reset(); 825 llvm::errs() << "Error while opening an input mirror file: " 826 << EC.message(); 827 } else { 828 InputMirrorStream->SetUnbuffered(); 829 } 830 } 831 832 #if !CLANGD_DECISION_FOREST 833 if (RankingModel == clangd::CodeCompleteOptions::DecisionForest) { 834 llvm::errs() << "Clangd was compiled without decision forest support.\n"; 835 return 1; 836 } 837 #endif 838 839 // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a 840 // trace flag in your editor's config is annoying, launching with 841 // `CLANGD_TRACE=trace.json vim` is easier. 842 std::optional<llvm::raw_fd_ostream> TracerStream; 843 std::unique_ptr<trace::EventTracer> Tracer; 844 const char *JSONTraceFile = getenv("CLANGD_TRACE"); 845 const char *MetricsCSVFile = getenv("CLANGD_METRICS"); 846 const char *TracerFile = JSONTraceFile ? JSONTraceFile : MetricsCSVFile; 847 if (TracerFile) { 848 std::error_code EC; 849 TracerStream.emplace(TracerFile, /*ref*/ EC, 850 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write); 851 if (EC) { 852 TracerStream.reset(); 853 llvm::errs() << "Error while opening trace file " << TracerFile << ": " 854 << EC.message(); 855 } else { 856 Tracer = (TracerFile == JSONTraceFile) 857 ? trace::createJSONTracer(*TracerStream, PrettyPrint) 858 : trace::createCSVMetricTracer(*TracerStream); 859 } 860 } 861 862 std::optional<trace::Session> TracingSession; 863 if (Tracer) 864 TracingSession.emplace(*Tracer); 865 866 // If a user ran `clangd` in a terminal without redirecting anything, 867 // it's somewhat likely they're confused about how to use clangd. 868 // Show them the help overview, which explains. 869 if (llvm::outs().is_displayed() && llvm::errs().is_displayed() && 870 !CheckFile.getNumOccurrences()) 871 llvm::errs() << Overview << "\n"; 872 // Use buffered stream to stderr (we still flush each log message). Unbuffered 873 // stream can cause significant (non-deterministic) latency for the logger. 874 llvm::errs().SetBuffered(); 875 StreamLogger Logger(llvm::errs(), LogLevel); 876 LoggingSession LoggingSession(Logger); 877 // Write some initial logs before we start doing any real work. 878 log("{0}", versionString()); 879 log("Features: {0}", featureString()); 880 log("PID: {0}", llvm::sys::Process::getProcessId()); 881 { 882 SmallString<128> CWD; 883 if (auto Err = llvm::sys::fs::current_path(CWD)) 884 log("Working directory unknown: {0}", Err.message()); 885 else 886 log("Working directory: {0}", CWD); 887 } 888 for (int I = 0; I < argc; ++I) 889 log("argv[{0}]: {1}", I, argv[I]); 890 if (auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar)) 891 log("{0}: {1}", FlagsEnvVar, *EnvFlags); 892 893 ClangdLSPServer::Options Opts; 894 Opts.UseDirBasedCDB = (CompileArgsFrom == FilesystemCompileArgs); 895 Opts.EnableExperimentalModulesSupport = ExperimentalModulesSupport; 896 897 switch (PCHStorage) { 898 case PCHStorageFlag::Memory: 899 Opts.StorePreamblesInMemory = true; 900 break; 901 case PCHStorageFlag::Disk: 902 Opts.StorePreamblesInMemory = false; 903 break; 904 } 905 if (!ResourceDir.empty()) 906 Opts.ResourceDir = ResourceDir; 907 Opts.BuildDynamicSymbolIndex = true; 908 std::vector<std::unique_ptr<SymbolIndex>> IdxStack; 909 #if CLANGD_ENABLE_REMOTE 910 if (RemoteIndexAddress.empty() != ProjectRoot.empty()) { 911 llvm::errs() << "remote-index-address and project-path have to be " 912 "specified at the same time."; 913 return 1; 914 } 915 if (!RemoteIndexAddress.empty()) { 916 if (IndexFile.empty()) { 917 log("Connecting to remote index at {0}", RemoteIndexAddress); 918 } else { 919 elog("When enabling remote index, IndexFile should not be specified. " 920 "Only one can be used at time. Remote index will ignored."); 921 } 922 } 923 #endif 924 Opts.BackgroundIndex = EnableBackgroundIndex; 925 Opts.BackgroundIndexPriority = BackgroundIndexPriority; 926 Opts.ReferencesLimit = ReferencesLimit; 927 Opts.Rename.LimitFiles = RenameFileLimit; 928 auto PAI = createProjectAwareIndex( 929 [SupportContainedRefs = Opts.EnableOutgoingCalls]( 930 const Config::ExternalIndexSpec &External, AsyncTaskRunner *Tasks) { 931 return loadExternalIndex(External, Tasks, SupportContainedRefs); 932 }, 933 Sync); 934 Opts.StaticIndex = PAI.get(); 935 Opts.AsyncThreadsCount = WorkerThreadsCount; 936 Opts.MemoryCleanup = getMemoryCleanupFunction(); 937 938 Opts.CodeComplete.IncludeIneligibleResults = IncludeIneligibleResults; 939 Opts.CodeComplete.Limit = LimitResults; 940 if (CompletionStyle.getNumOccurrences()) 941 Opts.CodeComplete.BundleOverloads = CompletionStyle != Detailed; 942 Opts.CodeComplete.ShowOrigins = ShowOrigins; 943 Opts.CodeComplete.InsertIncludes = HeaderInsertion; 944 Opts.CodeComplete.ImportInsertions = ImportInsertions; 945 if (!HeaderInsertionDecorators) { 946 Opts.CodeComplete.IncludeIndicator.Insert.clear(); 947 Opts.CodeComplete.IncludeIndicator.NoInsert.clear(); 948 } 949 Opts.CodeComplete.RunParser = CodeCompletionParse; 950 Opts.CodeComplete.RankingModel = RankingModel; 951 // FIXME: If we're using C++20 modules, force the lookup process to load 952 // external decls, since currently the index doesn't support C++20 modules. 953 Opts.CodeComplete.ForceLoadPreamble = ExperimentalModulesSupport; 954 955 RealThreadsafeFS TFS; 956 std::vector<std::unique_ptr<config::Provider>> ProviderStack; 957 std::unique_ptr<config::Provider> Config; 958 if (EnableConfig) { 959 ProviderStack.push_back( 960 config::Provider::fromAncestorRelativeYAMLFiles(".clangd", TFS)); 961 llvm::SmallString<256> UserConfig; 962 if (llvm::sys::path::user_config_directory(UserConfig)) { 963 llvm::sys::path::append(UserConfig, "clangd", "config.yaml"); 964 vlog("User config file is {0}", UserConfig); 965 ProviderStack.push_back(config::Provider::fromYAMLFile( 966 UserConfig, /*Directory=*/"", TFS, /*Trusted=*/true)); 967 } else { 968 elog("Couldn't determine user config file, not loading"); 969 } 970 } 971 ProviderStack.push_back(std::make_unique<FlagsConfigProvider>()); 972 std::vector<const config::Provider *> ProviderPointers; 973 for (const auto &P : ProviderStack) 974 ProviderPointers.push_back(P.get()); 975 Config = config::Provider::combine(std::move(ProviderPointers)); 976 Opts.ConfigProvider = Config.get(); 977 978 // Create an empty clang-tidy option. 979 TidyProvider ClangTidyOptProvider; 980 if (EnableClangTidy) { 981 std::vector<TidyProvider> Providers; 982 Providers.reserve(4 + EnableConfig); 983 Providers.push_back(provideEnvironment()); 984 Providers.push_back(provideClangTidyFiles(TFS)); 985 if (EnableConfig) 986 Providers.push_back(provideClangdConfig()); 987 Providers.push_back(provideDefaultChecks()); 988 Providers.push_back(disableUnusableChecks()); 989 ClangTidyOptProvider = combine(std::move(Providers)); 990 Opts.ClangTidyProvider = ClangTidyOptProvider; 991 } 992 Opts.UseDirtyHeaders = UseDirtyHeaders; 993 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions; 994 Opts.ImportInsertions = ImportInsertions; 995 Opts.QueryDriverGlobs = std::move(QueryDriverGlobs); 996 Opts.TweakFilter = [&](const Tweak &T) { 997 if (T.hidden() && !HiddenFeatures) 998 return false; 999 if (TweakList.getNumOccurrences()) 1000 return llvm::is_contained(TweakList, T.id()); 1001 return true; 1002 }; 1003 if (ForceOffsetEncoding != OffsetEncoding::UnsupportedEncoding) 1004 Opts.Encoding = ForceOffsetEncoding; 1005 1006 if (CheckFile.getNumOccurrences()) { 1007 llvm::SmallString<256> Path; 1008 if (auto Error = 1009 llvm::sys::fs::real_path(CheckFile, Path, /*expand_tilde=*/true)) { 1010 elog("Failed to resolve path {0}: {1}", CheckFile, Error.message()); 1011 return 1; 1012 } 1013 log("Entering check mode (no LSP server)"); 1014 return check(Path, TFS, Opts) 1015 ? 0 1016 : static_cast<int>(ErrorResultCode::CheckFailed); 1017 } 1018 1019 // Initialize and run ClangdLSPServer. 1020 // Change stdin to binary to not lose \r\n on windows. 1021 llvm::sys::ChangeStdinToBinary(); 1022 std::unique_ptr<Transport> TransportLayer; 1023 if (getenv("CLANGD_AS_XPC_SERVICE")) { 1024 #if CLANGD_BUILD_XPC 1025 log("Starting LSP over XPC service"); 1026 TransportLayer = newXPCTransport(); 1027 #else 1028 llvm::errs() << "This clangd binary wasn't built with XPC support.\n"; 1029 return static_cast<int>(ErrorResultCode::CantRunAsXPCService); 1030 #endif 1031 } else { 1032 log("Starting LSP over stdin/stdout"); 1033 TransportLayer = newJSONTransport( 1034 stdin, llvm::outs(), InputMirrorStream ? &*InputMirrorStream : nullptr, 1035 PrettyPrint, InputStyle); 1036 } 1037 if (!PathMappingsArg.empty()) { 1038 auto Mappings = parsePathMappings(PathMappingsArg); 1039 if (!Mappings) { 1040 elog("Invalid -path-mappings: {0}", Mappings.takeError()); 1041 return 1; 1042 } 1043 TransportLayer = createPathMappingTransport(std::move(TransportLayer), 1044 std::move(*Mappings)); 1045 } 1046 1047 ClangdLSPServer LSPServer(*TransportLayer, TFS, Opts); 1048 llvm::set_thread_name("clangd.main"); 1049 int ExitCode = LSPServer.run() 1050 ? 0 1051 : static_cast<int>(ErrorResultCode::NoShutdownRequest); 1052 log("LSP finished, exiting with status {0}", ExitCode); 1053 1054 // There may still be lingering background threads (e.g. slow requests 1055 // whose results will be dropped, background index shutting down). 1056 // 1057 // These should terminate quickly, and ~ClangdLSPServer blocks on them. 1058 // However if a bug causes them to run forever, we want to ensure the process 1059 // eventually exits. As clangd isn't directly user-facing, an editor can 1060 // "leak" clangd processes. Crashing in this case contains the damage. 1061 abortAfterTimeout(std::chrono::minutes(5)); 1062 1063 return ExitCode; 1064 } 1065 1066 } // namespace clangd 1067 } // namespace clang 1068