xref: /llvm-project/clang-tools-extra/clangd/tool/ClangdMain.cpp (revision fe1f64e7e935c9905a115842183ea29dd1312dfe)
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