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