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