clang-tools  10.0.0
ClangdMain.cpp
Go to the documentation of this file.
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 "Features.inc"
12 #include "Path.h"
13 #include "PathMapping.h"
14 #include "Protocol.h"
15 #include "Shutdown.h"
16 #include "Trace.h"
17 #include "Transport.h"
18 #include "index/Background.h"
19 #include "index/Serialization.h"
20 #include "clang/Basic/Version.h"
21 #include "clang/Format/Format.h"
22 #include "llvm/ADT/Optional.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/Process.h"
28 #include "llvm/Support/Program.h"
29 #include "llvm/Support/Signals.h"
30 #include "llvm/Support/TargetSelect.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include <chrono>
33 #include <cstdlib>
34 #include <iostream>
35 #include <memory>
36 #include <mutex>
37 #include <string>
38 #include <thread>
39 
40 #ifndef _WIN32
41 #include <unistd.h>
42 #endif
43 
44 namespace clang {
45 namespace clangd {
46 namespace {
47 
48 using llvm::cl::cat;
49 using llvm::cl::CommaSeparated;
50 using llvm::cl::desc;
51 using llvm::cl::Hidden;
52 using llvm::cl::init;
53 using llvm::cl::list;
54 using llvm::cl::opt;
55 using llvm::cl::OptionCategory;
56 using llvm::cl::values;
57 
58 // All flags must be placed in a category, or they will be shown neither in
59 // --help, nor --help-hidden!
60 OptionCategory CompileCommands("clangd compilation flags options");
61 OptionCategory Features("clangd feature options");
62 OptionCategory Misc("clangd miscellaneous options");
63 OptionCategory Protocol("clangd protocol and logging options");
64 const OptionCategory *ClangdCategories[] = {&Features, &Protocol,
65  &CompileCommands, &Misc};
66 
67 enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs };
68 opt<CompileArgsFrom> CompileArgsFrom{
69  "compile_args_from",
70  cat(CompileCommands),
71  desc("The source of compile commands"),
72  values(clEnumValN(LSPCompileArgs, "lsp",
73  "All compile commands come from LSP and "
74  "'compile_commands.json' files are ignored"),
75  clEnumValN(FilesystemCompileArgs, "filesystem",
76  "All compile commands come from the "
77  "'compile_commands.json' files")),
78  init(FilesystemCompileArgs),
79  Hidden,
80 };
81 
82 opt<Path> CompileCommandsDir{
83  "compile-commands-dir",
84  cat(CompileCommands),
85  desc("Specify a path to look for compile_commands.json. If path "
86  "is invalid, clangd will look in the current directory and "
87  "parent paths of each source file"),
88 };
89 
90 opt<Path> ResourceDir{
91  "resource-dir",
92  cat(CompileCommands),
93  desc("Directory for system clang headers"),
94  init(""),
95  Hidden,
96 };
97 
98 list<std::string> QueryDriverGlobs{
99  "query-driver",
100  cat(CompileCommands),
101  desc(
102  "Comma separated list of globs for white-listing gcc-compatible "
103  "drivers that are safe to execute. Drivers matching any of these globs "
104  "will be used to extract system includes. e.g. "
105  "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"),
106  CommaSeparated,
107 };
108 
109 // FIXME: Flags are the wrong mechanism for user preferences.
110 // We should probably read a dotfile or similar.
111 opt<bool> AllScopesCompletion{
112  "all-scopes-completion",
113  cat(Features),
114  desc("If set to true, code completion will include index symbols that are "
115  "not defined in the scopes (e.g. "
116  "namespaces) visible from the code completion point. Such completions "
117  "can insert scope qualifiers"),
118  init(true),
119 };
120 
121 opt<bool> ShowOrigins{
122  "debug-origin",
123  cat(Features),
124  desc("Show origins of completion items"),
125  init(CodeCompleteOptions().ShowOrigins),
126  Hidden,
127 };
128 
129 opt<bool> EnableBackgroundIndex{
130  "background-index",
131  cat(Features),
132  desc("Index project code in the background and persist index on disk."),
133  init(true),
134 };
135 
136 opt<bool> EnableClangTidy{
137  "clang-tidy",
138  cat(Features),
139  desc("Enable clang-tidy diagnostics"),
140  init(true),
141 };
142 
143 opt<std::string> ClangTidyChecks{
144  "clang-tidy-checks",
145  cat(Features),
146  desc("List of clang-tidy checks to run (this will override "
147  ".clang-tidy files). Only meaningful when -clang-tidy flag is on"),
148  init(""),
149 };
150 
151 opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{
152  "completion-parse",
153  cat(Features),
154  desc("Whether the clang-parser is used for code-completion"),
155  values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always",
156  "Block until the parser can be used"),
157  clEnumValN(CodeCompleteOptions::ParseIfReady, "auto",
158  "Use text-based completion if the parser "
159  "is not ready"),
160  clEnumValN(CodeCompleteOptions::NeverParse, "never",
161  "Always used text-based completion")),
162  init(CodeCompleteOptions().RunParser),
163  Hidden,
164 };
165 
166 // FIXME: also support "plain" style where signatures are always omitted.
167 enum CompletionStyleFlag { Detailed, Bundled };
168 opt<CompletionStyleFlag> CompletionStyle{
169  "completion-style",
170  cat(Features),
171  desc("Granularity of code completion suggestions"),
172  values(clEnumValN(Detailed, "detailed",
173  "One completion item for each semantically distinct "
174  "completion, with full type information"),
175  clEnumValN(Bundled, "bundled",
176  "Similar completion items (e.g. function overloads) are "
177  "combined. Type information shown where possible")),
178 };
179 
180 opt<std::string> FallbackStyle{
181  "fallback-style",
182  cat(Features),
183  desc("clang-format style to apply by default when "
184  "no .clang-format file is found"),
185  init(clang::format::DefaultFallbackStyle),
186 };
187 
188 opt<bool> EnableFunctionArgSnippets{
189  "function-arg-placeholders",
190  cat(Features),
191  desc("When disabled, completions contain only parentheses for "
192  "function calls. When enabled, completions also contain "
193  "placeholders for method parameters"),
194  init(CodeCompleteOptions().EnableFunctionArgSnippets),
195  Hidden,
196 };
197 
198 opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{
199  "header-insertion",
200  cat(Features),
201  desc("Add #include directives when accepting code completions"),
202  init(CodeCompleteOptions().InsertIncludes),
203  values(
204  clEnumValN(CodeCompleteOptions::IWYU, "iwyu",
205  "Include what you use. "
206  "Insert the owning header for top-level symbols, unless the "
207  "header is already directly included or the symbol is "
208  "forward-declared"),
209  clEnumValN(
211  "Never insert #include directives as part of code completion")),
212 };
213 
214 opt<bool> HeaderInsertionDecorators{
215  "header-insertion-decorators",
216  cat(Features),
217  desc("Prepend a circular dot or space before the completion "
218  "label, depending on whether "
219  "an include line will be inserted or not"),
220  init(true),
221 };
222 
223 opt<bool> HiddenFeatures{
224  "hidden-features",
225  cat(Features),
226  desc("Enable hidden features mostly useful to clangd developers"),
227  init(false),
228  Hidden,
229 };
230 
231 opt<bool> IncludeIneligibleResults{
232  "include-ineligible-results",
233  cat(Features),
234  desc("Include ineligible completion results (e.g. private members)"),
235  init(CodeCompleteOptions().IncludeIneligibleResults),
236  Hidden,
237 };
238 
239 opt<bool> EnableIndex{
240  "index",
241  cat(Features),
242  desc("Enable index-based features. By default, clangd maintains an index "
243  "built from symbols in opened files. Global index support needs to "
244  "enabled separatedly"),
245  init(true),
246  Hidden,
247 };
248 
249 opt<int> LimitResults{
250  "limit-results",
251  cat(Features),
252  desc("Limit the number of results returned by clangd. "
253  "0 means no limit (default=100)"),
254  init(100),
255 };
256 
257 opt<bool> SuggestMissingIncludes{
258  "suggest-missing-includes",
259  cat(Features),
260  desc("Attempts to fix diagnostic errors caused by missing "
261  "includes using index"),
262  init(true),
263 };
264 
265 list<std::string> TweakList{
266  "tweaks",
267  cat(Features),
268  desc("Specify a list of Tweaks to enable (only for clangd developers)."),
269  Hidden,
270  CommaSeparated,
271 };
272 
273 opt<bool> CrossFileRename{
274  "cross-file-rename",
275  cat(Features),
276  desc("Enable cross-file rename feature. Note that this feature is "
277  "experimental and may lead to broken code or incomplete rename "
278  "results"),
279  init(false),
280  Hidden,
281 };
282 
283 opt<unsigned> WorkerThreadsCount{
284  "j",
285  cat(Misc),
286  desc("Number of async workers used by clangd. Background index also "
287  "uses this many workers."),
289 };
290 
291 opt<Path> IndexFile{
292  "index-file",
293  cat(Misc),
294  desc(
295  "Index file to build the static index. The file must have been created "
296  "by a compatible clangd-indexer\n"
297  "WARNING: This option is experimental only, and will be removed "
298  "eventually. Don't rely on it"),
299  init(""),
300  Hidden,
301 };
302 
303 opt<bool> Test{
304  "lit-test",
305  cat(Misc),
306  desc("Abbreviation for -input-style=delimited -pretty -sync "
307  "-enable-test-scheme -log=verbose. "
308  "Intended to simplify lit tests"),
309  init(false),
310  Hidden,
311 };
312 
313 enum PCHStorageFlag { Disk, Memory };
314 opt<PCHStorageFlag> PCHStorage{
315  "pch-storage",
316  cat(Misc),
317  desc("Storing PCHs in memory increases memory usages, but may "
318  "improve performance"),
319  values(
320  clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"),
321  clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")),
322  init(PCHStorageFlag::Disk),
323 };
324 
325 opt<bool> Sync{
326  "sync",
327  cat(Misc),
328  desc("Handle client requests on main thread. Background index still uses "
329  "its own thread."),
330  init(false),
331  Hidden,
332 };
333 
334 opt<JSONStreamStyle> InputStyle{
335  "input-style",
336  cat(Protocol),
337  desc("Input JSON stream encoding"),
338  values(
339  clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"),
340  clEnumValN(JSONStreamStyle::Delimited, "delimited",
341  "messages delimited by --- lines, with # comment support")),
343  Hidden,
344 };
345 
346 opt<bool> EnableTestScheme{
347  "enable-test-uri-scheme",
348  cat(Protocol),
349  desc("Enable 'test:' URI scheme. Only use in lit tests"),
350  init(false),
351  Hidden,
352 };
353 
354 opt<std::string> PathMappingsArg{
355  "path-mappings",
356  cat(Protocol),
357  desc(
358  "Translates between client paths (as seen by a remote editor) and "
359  "server paths (where clangd sees files on disk). "
360  "Comma separated list of '<client_path>=<server_path>' pairs, the "
361  "first entry matching a given path is used. "
362  "e.g. /home/project/incl=/opt/include,/home/project=/workarea/project"),
363  init(""),
364 };
365 
366 opt<Path> InputMirrorFile{
367  "input-mirror-file",
368  cat(Protocol),
369  desc("Mirror all LSP input to the specified file. Useful for debugging"),
370  init(""),
371  Hidden,
372 };
373 
374 opt<Logger::Level> LogLevel{
375  "log",
376  cat(Protocol),
377  desc("Verbosity of log messages written to stderr"),
378  values(clEnumValN(Logger::Error, "error", "Error messages only"),
379  clEnumValN(Logger::Info, "info", "High level execution tracing"),
380  clEnumValN(Logger::Debug, "verbose", "Low level details")),
381  init(Logger::Info),
382 };
383 
384 opt<OffsetEncoding> ForceOffsetEncoding{
385  "offset-encoding",
386  cat(Protocol),
387  desc("Force the offsetEncoding used for character positions. "
388  "This bypasses negotiation via client capabilities"),
389  values(
390  clEnumValN(OffsetEncoding::UTF8, "utf-8", "Offsets are in UTF-8 bytes"),
391  clEnumValN(OffsetEncoding::UTF16, "utf-16",
392  "Offsets are in UTF-16 code units"),
393  clEnumValN(OffsetEncoding::UTF32, "utf-32",
394  "Offsets are in unicode codepoints")),
396 };
397 
398 opt<bool> PrettyPrint{
399  "pretty",
400  cat(Protocol),
401  desc("Pretty-print JSON output"),
402  init(false),
403 };
404 
405 /// Supports a test URI scheme with relaxed constraints for lit tests.
406 /// The path in a test URI will be combined with a platform-specific fake
407 /// directory to form an absolute path. For example, test:///a.cpp is resolved
408 /// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix.
409 class TestScheme : public URIScheme {
410 public:
411  llvm::Expected<std::string>
412  getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body,
413  llvm::StringRef /*HintPath*/) const override {
414  using namespace llvm::sys;
415  // Still require "/" in body to mimic file scheme, as we want lengths of an
416  // equivalent URI in both schemes to be the same.
417  if (!Body.startswith("/"))
418  return llvm::make_error<llvm::StringError>(
419  "Expect URI body to be an absolute path starting with '/': " + Body,
420  llvm::inconvertibleErrorCode());
421  Body = Body.ltrim('/');
422  llvm::SmallVector<char, 16> Path(Body.begin(), Body.end());
423  path::native(Path);
424  fs::make_absolute(TestScheme::TestDir, Path);
425  return std::string(Path.begin(), Path.end());
426  }
427 
428  llvm::Expected<URI>
429  uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override {
430  llvm::StringRef Body = AbsolutePath;
431  if (!Body.consume_front(TestScheme::TestDir)) {
432  return llvm::make_error<llvm::StringError>(
433  "Path " + AbsolutePath + " doesn't start with root " + TestDir,
434  llvm::inconvertibleErrorCode());
435  }
436 
437  return URI("test", /*Authority=*/"",
438  llvm::sys::path::convert_to_slash(Body));
439  }
440 
441 private:
442  const static char TestDir[];
443 };
444 
445 #ifdef _WIN32
446 const char TestScheme::TestDir[] = "C:\\clangd-test";
447 #else
448 const char TestScheme::TestDir[] = "/clangd-test";
449 #endif
450 
451 } // namespace
452 } // namespace clangd
453 } // namespace clang
454 
455 enum class ErrorResultCode : int {
456  NoShutdownRequest = 1,
458 };
459 
460 int main(int argc, char *argv[]) {
461  using namespace clang;
462  using namespace clang::clangd;
463 
464  llvm::InitializeAllTargetInfos();
465  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
466  llvm::sys::SetInterruptFunction(&requestShutdown);
467  llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) {
468  OS << clang::getClangToolFullVersion("clangd") << "\n";
469  });
470  const char *FlagsEnvVar = "CLANGD_FLAGS";
471  const char *Overview =
472  R"(clangd is a language server that provides IDE-like features to editors.
473 
474 It should be used via an editor plugin rather than invoked directly. For more information, see:
475  https://clang.llvm.org/extra/clangd/
476  https://microsoft.github.io/language-server-protocol/
477 
478 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
479 )";
480  llvm::cl::HideUnrelatedOptions(ClangdCategories);
481  llvm::cl::ParseCommandLineOptions(argc, argv, Overview,
482  /*Errs=*/nullptr, FlagsEnvVar);
483  if (Test) {
484  Sync = true;
485  InputStyle = JSONStreamStyle::Delimited;
486  LogLevel = Logger::Verbose;
487  PrettyPrint = true;
488  // Disable background index on lit tests by default to prevent disk writes.
489  if (!EnableBackgroundIndex.getNumOccurrences())
490  EnableBackgroundIndex = false;
491  // Ensure background index makes progress.
492  else if (EnableBackgroundIndex)
494  }
495  if (Test || EnableTestScheme) {
496  static URISchemeRegistry::Add<TestScheme> X(
497  "test", "Test scheme for clangd lit tests.");
498  }
499 
500  if (!Sync && WorkerThreadsCount == 0) {
501  llvm::errs() << "A number of worker threads cannot be 0. Did you mean to "
502  "specify -sync?";
503  return 1;
504  }
505 
506  if (Sync) {
507  if (WorkerThreadsCount.getNumOccurrences())
508  llvm::errs() << "Ignoring -j because -sync is set.\n";
509  WorkerThreadsCount = 0;
510  }
511  if (FallbackStyle.getNumOccurrences())
512  clang::format::DefaultFallbackStyle = FallbackStyle.c_str();
513 
514  // Validate command line arguments.
515  llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
516  if (!InputMirrorFile.empty()) {
517  std::error_code EC;
518  InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC,
519  llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
520  if (EC) {
521  InputMirrorStream.reset();
522  llvm::errs() << "Error while opening an input mirror file: "
523  << EC.message();
524  } else {
525  InputMirrorStream->SetUnbuffered();
526  }
527  }
528 
529  // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a
530  // trace flag in your editor's config is annoying, launching with
531  // `CLANGD_TRACE=trace.json vim` is easier.
532  llvm::Optional<llvm::raw_fd_ostream> TraceStream;
533  std::unique_ptr<trace::EventTracer> Tracer;
534  if (auto *TraceFile = getenv("CLANGD_TRACE")) {
535  std::error_code EC;
536  TraceStream.emplace(TraceFile, /*ref*/ EC,
537  llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
538  if (EC) {
539  TraceStream.reset();
540  llvm::errs() << "Error while opening trace file " << TraceFile << ": "
541  << EC.message();
542  } else {
543  Tracer = trace::createJSONTracer(*TraceStream, PrettyPrint);
544  }
545  }
546 
547  llvm::Optional<trace::Session> TracingSession;
548  if (Tracer)
549  TracingSession.emplace(*Tracer);
550 
551  // If a user ran `clangd` in a terminal without redirecting anything,
552  // it's somewhat likely they're confused about how to use clangd.
553  // Show them the help overview, which explains.
554  if (llvm::outs().is_displayed() && llvm::errs().is_displayed())
555  llvm::errs() << Overview << "\n";
556  // Use buffered stream to stderr (we still flush each log message). Unbuffered
557  // stream can cause significant (non-deterministic) latency for the logger.
558  llvm::errs().SetBuffered();
559  StreamLogger Logger(llvm::errs(), LogLevel);
561  // Write some initial logs before we start doing any real work.
562  log("{0}", clang::getClangToolFullVersion("clangd"));
563 // FIXME: abstract this better, and print PID on windows too.
564 #ifndef _WIN32
565  log("PID: {0}", getpid());
566 #endif
567  {
568  SmallString<128> CWD;
569  if (auto Err = llvm::sys::fs::current_path(CWD))
570  log("Working directory unknown: {0}", Err.message());
571  else
572  log("Working directory: {0}", CWD);
573  }
574  for (int I = 0; I < argc; ++I)
575  log("argv[{0}]: {1}", I, argv[I]);
576  if (auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
577  log("{0}: {1}", FlagsEnvVar, *EnvFlags);
578 
579  // If --compile-commands-dir arg was invoked, check value and override default
580  // path.
581  llvm::Optional<Path> CompileCommandsDirPath;
582  if (!CompileCommandsDir.empty()) {
583  if (llvm::sys::fs::exists(CompileCommandsDir)) {
584  // We support passing both relative and absolute paths to the
585  // --compile-commands-dir argument, but we assume the path is absolute in
586  // the rest of clangd so we make sure the path is absolute before
587  // continuing.
588  llvm::SmallString<128> Path(CompileCommandsDir);
589  if (std::error_code EC = llvm::sys::fs::make_absolute(Path)) {
590  llvm::errs() << "Error while converting the relative path specified by "
591  "--compile-commands-dir to an absolute path: "
592  << EC.message() << ". The argument will be ignored.\n";
593  } else {
594  CompileCommandsDirPath = Path.str();
595  }
596  } else {
597  llvm::errs()
598  << "Path specified by --compile-commands-dir does not exist. The "
599  "argument will be ignored.\n";
600  }
601  }
602 
604  switch (PCHStorage) {
605  case PCHStorageFlag::Memory:
606  Opts.StorePreamblesInMemory = true;
607  break;
608  case PCHStorageFlag::Disk:
609  Opts.StorePreamblesInMemory = false;
610  break;
611  }
612  if (!ResourceDir.empty())
613  Opts.ResourceDir = ResourceDir;
614  Opts.BuildDynamicSymbolIndex = EnableIndex;
615  Opts.BackgroundIndex = EnableBackgroundIndex;
616  std::unique_ptr<SymbolIndex> StaticIdx;
617  std::future<void> AsyncIndexLoad; // Block exit while loading the index.
618  if (EnableIndex && !IndexFile.empty()) {
619  // Load the index asynchronously. Meanwhile SwapIndex returns no results.
620  SwapIndex *Placeholder;
621  StaticIdx.reset(Placeholder = new SwapIndex(std::make_unique<MemIndex>()));
622  AsyncIndexLoad = runAsync<void>([Placeholder] {
623  if (auto Idx = loadIndex(IndexFile, /*UseDex=*/true))
624  Placeholder->reset(std::move(Idx));
625  });
626  if (Sync)
627  AsyncIndexLoad.wait();
628  }
629  Opts.StaticIndex = StaticIdx.get();
630  Opts.AsyncThreadsCount = WorkerThreadsCount;
631  Opts.CrossFileRename = CrossFileRename;
632 
634  CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
635  CCOpts.Limit = LimitResults;
636  if (CompletionStyle.getNumOccurrences())
637  CCOpts.BundleOverloads = CompletionStyle != Detailed;
638  CCOpts.ShowOrigins = ShowOrigins;
639  CCOpts.InsertIncludes = HeaderInsertion;
640  if (!HeaderInsertionDecorators) {
641  CCOpts.IncludeIndicator.Insert.clear();
642  CCOpts.IncludeIndicator.NoInsert.clear();
643  }
644  CCOpts.SpeculativeIndexRequest = Opts.StaticIndex;
645  CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets;
646  CCOpts.AllScopes = AllScopesCompletion;
647  CCOpts.RunParser = CodeCompletionParse;
648 
650  // Initialize and run ClangdLSPServer.
651  // Change stdin to binary to not lose \r\n on windows.
652  llvm::sys::ChangeStdinToBinary();
653 
654  std::unique_ptr<Transport> TransportLayer;
655  if (getenv("CLANGD_AS_XPC_SERVICE")) {
656 #if CLANGD_BUILD_XPC
657  log("Starting LSP over XPC service");
658  TransportLayer = newXPCTransport();
659 #else
660  llvm::errs() << "This clangd binary wasn't built with XPC support.\n";
662 #endif
663  } else {
664  log("Starting LSP over stdin/stdout");
665  TransportLayer = newJSONTransport(
666  stdin, llvm::outs(),
667  InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,
668  PrettyPrint, InputStyle);
669  }
670  if (!PathMappingsArg.empty()) {
671  auto Mappings = parsePathMappings(PathMappingsArg);
672  if (!Mappings) {
673  elog("Invalid -path-mappings: {0}", Mappings.takeError());
674  return 1;
675  }
676  TransportLayer = createPathMappingTransport(std::move(TransportLayer),
677  std::move(*Mappings));
678  }
679  // Create an empty clang-tidy option.
680  std::mutex ClangTidyOptMu;
681  std::unique_ptr<tidy::ClangTidyOptionsProvider>
682  ClangTidyOptProvider; /*GUARDED_BY(ClangTidyOptMu)*/
683  if (EnableClangTidy) {
684  auto OverrideClangTidyOptions = tidy::ClangTidyOptions::getDefaults();
685  OverrideClangTidyOptions.Checks = ClangTidyChecks;
686  ClangTidyOptProvider = std::make_unique<tidy::FileOptionsProvider>(
688  /* Default */ tidy::ClangTidyOptions::getDefaults(),
689  /* Override */ OverrideClangTidyOptions, FSProvider.getFileSystem());
690  Opts.GetClangTidyOptions = [&](llvm::vfs::FileSystem &,
691  llvm::StringRef File) {
692  // This function must be thread-safe and tidy option providers are not.
693  std::lock_guard<std::mutex> Lock(ClangTidyOptMu);
694  // FIXME: use the FS provided to the function.
695  return ClangTidyOptProvider->getOptions(File);
696  };
697  }
698  Opts.SuggestMissingIncludes = SuggestMissingIncludes;
699  Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
700 
701  Opts.TweakFilter = [&](const Tweak &T) {
702  if (T.hidden() && !HiddenFeatures)
703  return false;
704  if (TweakList.getNumOccurrences())
705  return llvm::is_contained(TweakList, T.id());
706  return true;
707  };
708  llvm::Optional<OffsetEncoding> OffsetEncodingFromFlag;
709  if (ForceOffsetEncoding != OffsetEncoding::UnsupportedEncoding)
710  OffsetEncodingFromFlag = ForceOffsetEncoding;
711  ClangdLSPServer LSPServer(
712  *TransportLayer, FSProvider, CCOpts, CompileCommandsDirPath,
713  /*UseDirBasedCDB=*/CompileArgsFrom == FilesystemCompileArgs,
714  OffsetEncodingFromFlag, Opts);
715  llvm::set_thread_name("clangd.main");
716  int ExitCode = LSPServer.run()
717  ? 0
718  : static_cast<int>(ErrorResultCode::NoShutdownRequest);
719  log("LSP finished, exiting with status {0}", ExitCode);
720 
721  // There may still be lingering background threads (e.g. slow requests
722  // whose results will be dropped, background index shutting down).
723  //
724  // These should terminate quickly, and ~ClangdLSPServer blocks on them.
725  // However if a bug causes them to run forever, we want to ensure the process
726  // eventually exits. As clangd isn't directly user-facing, an editor can
727  // "leak" clangd processes. Crashing in this case contains the damage.
728  abortAfterTimeout(std::chrono::minutes(5));
729 
730  return ExitCode;
731 }
bool ShowOrigins
Expose origins of completion items in the label (for debugging).
Definition: CodeComplete.h:86
std::function< bool(const Tweak &)> TweakFilter
Returns true if the tweak should be enabled.
Definition: ClangdServer.h:141
size_t Limit
Limit the number of results returned (0 means no limit).
Definition: CodeComplete.h:71
ErrorResultCode
Definition: ClangdMain.cpp:455
Always use text-based completion.
Definition: CodeComplete.h:130
int main(int argc, char *argv[])
Definition: ClangdMain.cpp:460
std::unique_ptr< SymbolIndex > loadIndex(llvm::StringRef SymbolFilename, bool UseDex)
bool BackgroundIndex
If true, ClangdServer automatically indexes files in the current project on background threads...
Definition: ClangdServer.h:101
URIScheme is an extension point for teaching clangd to recognize a custom URI scheme.
Definition: URI.h:108
std::unique_ptr< Transport > newXPCTransport()
void requestShutdown()
Sets a flag to indicate that clangd was sent a shutdown signal, and the transport loop should exit at...
Definition: Shutdown.cpp:28
bool run()
Run LSP server loop, communicating with the Transport provided in the constructor.
Run the parser if inputs (preamble) are ready.
Definition: CodeComplete.h:128
void abortAfterTimeout(std::chrono::seconds Timeout)
Causes this process to crash if still running after Timeout.
Definition: Shutdown.cpp:18
def make_absolute(f, directory)
unsigned AsyncThreadsCount
To process requests asynchronously, ClangdServer spawns worker threads.
Definition: ClangdServer.h:86
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
bool BuildDynamicSymbolIndex
If true, ClangdServer builds a dynamic in-memory index for symbols in opened files and uses the index...
Definition: ClangdServer.h:96
MockFSProvider FSProvider
static void preventThreadStarvationInTests()
Interface to allow custom logging in clangd.
Definition: Logger.h:23
bool SpeculativeIndexRequest
If set to true, this will send an asynchronous speculative index request, based on the index request ...
Definition: CodeComplete.h:96
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
llvm::Expected< PathMappings > parsePathMappings(llvm::StringRef RawPathMappings)
Parse the command line RawPathMappings (e.g.
Only one LoggingSession can be active at a time.
Definition: Logger.h:77
bool IncludeIneligibleResults
Include results that are not legal completions in the current context.
Definition: CodeComplete.h:61
enum clang::clangd::CodeCompleteOptions::CodeCompletionParse RunParser
std::unique_ptr< Transport > newJSONTransport(std::FILE *In, llvm::raw_ostream &Out, llvm::raw_ostream *InMirror, bool Pretty, JSONStreamStyle Style)
llvm::Optional< bool > BundleOverloads
Combine overloads into a single completion item where possible.
Definition: CodeComplete.h:67
std::unique_ptr< Transport > createPathMappingTransport(std::unique_ptr< Transport > Transp, PathMappings Mappings)
Creates a wrapping transport over Transp that applies the Mappings to all inbound and outbound LSP me...
unsigned getDefaultAsyncThreadsCount()
Returns a number of a default async threads to use for TUScheduler.
Block until we can run the parser (e.g.
Definition: CodeComplete.h:125
bool StorePreamblesInMemory
Cached preambles are potentially large. If false, store them on disk.
Definition: ClangdServer.h:92
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static URISchemeRegistry::Add< TestScheme > X(TestScheme::Scheme, "Test schema")
llvm::Optional< std::string > ResourceDir
The resource directory is used to find internal headers, overriding defaults and -resource-dir compil...
Definition: ClangdServer.h:122
std::unique_ptr< EventTracer > createJSONTracer(llvm::raw_ostream &OS, bool Pretty)
Create an instance of EventTracer that produces an output in the Trace Event format supported by Chro...
Definition: Trace.cpp:200
struct clang::clangd::CodeCompleteOptions::IncludeInsertionIndicator IncludeIndicator
std::vector< std::string > QueryDriverGlobs
Clangd will execute compiler drivers matching one of these globs to fetch system include path...
Definition: ClangdServer.h:132
A URI describes the location of a source file.
Definition: URI.h:28
An interface base for small context-sensitive refactoring actions.
Definition: Tweak.h:46
bool EnableFunctionArgSnippets
Whether to generate snippets for function arguments on code-completion.
Definition: CodeComplete.h:111
ClangTidyOptionsBuilder GetClangTidyOptions
If set, enable clang-tidy in clangd and use to it get clang-tidy configurations for a particular file...
Definition: ClangdServer.h:111
bool AllScopes
Whether to include index symbols that are not defined in the scopes visible from the code completion ...
Definition: CodeComplete.h:118
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getFileSystem() const override
Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
Definition: FSProvider.cpp:75
static ClangTidyOptions getDefaults()
These options are used for all settings that haven&#39;t been overridden by the OptionsProvider.
This class exposes ClangdServer&#39;s capabilities via Language Server Protocol.
SymbolIndex * StaticIndex
If set, use this index to augment code completion results.
Definition: ClangdServer.h:104
void reset(std::unique_ptr< SymbolIndex >)
Definition: Index.cpp:20
bool CrossFileRename
Enable cross-file rename feature.
Definition: ClangdServer.h:138
enum clang::clangd::CodeCompleteOptions::IncludeInsertion InsertIncludes