1 //===--- ClangdMain.cpp - clangd server loop ------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ClangdMain.h"
10 #include "ClangdLSPServer.h"
11 #include "CodeComplete.h"
14 #include "ConfigProvider.h"
16 #include "IncludeCleaner.h"
17 #include "PathMapping.h"
19 #include "TidyProvider.h"
20 #include "Transport.h"
21 #include "index/Background.h"
22 #include "index/Index.h"
23 #include "index/MemIndex.h"
24 #include "index/Merge.h"
25 #include "index/ProjectAware.h"
26 #include "index/remote/Client.h"
27 #include "support/Path.h"
28 #include "support/Shutdown.h"
29 #include "support/ThreadCrashReporter.h"
30 #include "support/ThreadsafeFS.h"
31 #include "support/Trace.h"
32 #include "clang/Basic/Stack.h"
33 #include "clang/Format/Format.h"
34 #include "llvm/ADT/SmallString.h"
35 #include "llvm/ADT/StringRef.h"
36 #include "llvm/Support/CommandLine.h"
37 #include "llvm/Support/FileSystem.h"
38 #include "llvm/Support/InitLLVM.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/Process.h"
41 #include "llvm/Support/Program.h"
42 #include "llvm/Support/Signals.h"
43 #include "llvm/Support/TargetSelect.h"
44 #include "llvm/Support/raw_ostream.h"
66 // Implemented in Check.cpp.
67 bool check(const llvm::StringRef File
, const ThreadsafeFS
&TFS
,
68 const ClangdLSPServer::Options
&Opts
);
73 using llvm::cl::CommaSeparated
;
75 using llvm::cl::Hidden
;
79 using llvm::cl::OptionCategory
;
80 using llvm::cl::ValueOptional
;
81 using llvm::cl::values
;
83 // All flags must be placed in a category, or they will be shown neither in
84 // --help, nor --help-hidden!
85 OptionCategory
CompileCommands("clangd compilation flags options");
86 OptionCategory
Features("clangd feature options");
87 OptionCategory
Misc("clangd miscellaneous options");
88 OptionCategory
Protocol("clangd protocol and logging options");
89 OptionCategory
Retired("clangd flags no longer in use");
90 const OptionCategory
*ClangdCategories
[] = {&Features
, &Protocol
,
91 &CompileCommands
, &Misc
, &Retired
};
93 template <typename T
> class RetiredFlag
{
97 RetiredFlag(llvm::StringRef Name
)
98 : Option(Name
, cat(Retired
), desc("Obsolete flag, ignored"), Hidden
,
99 llvm::cl::callback([Name
](const T
&) {
101 << "The flag `-" << Name
<< "` is obsolete and ignored.\n";
105 enum CompileArgsFrom
{ LSPCompileArgs
, FilesystemCompileArgs
};
106 opt
<CompileArgsFrom
> CompileArgsFrom
{
108 cat(CompileCommands
),
109 desc("The source of compile commands"),
110 values(clEnumValN(LSPCompileArgs
, "lsp",
111 "All compile commands come from LSP and "
112 "'compile_commands.json' files are ignored"),
113 clEnumValN(FilesystemCompileArgs
, "filesystem",
114 "All compile commands come from the "
115 "'compile_commands.json' files")),
116 init(FilesystemCompileArgs
),
120 opt
<Path
> CompileCommandsDir
{
121 "compile-commands-dir",
122 cat(CompileCommands
),
123 desc("Specify a path to look for compile_commands.json. If path "
124 "is invalid, clangd will look in the current directory and "
125 "parent paths of each source file"),
128 opt
<Path
> ResourceDir
{
130 cat(CompileCommands
),
131 desc("Directory for system clang headers"),
136 list
<std::string
> QueryDriverGlobs
{
138 cat(CompileCommands
),
140 "Comma separated list of globs for white-listing gcc-compatible "
141 "drivers that are safe to execute. Drivers matching any of these globs "
142 "will be used to extract system includes. e.g. "
143 "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"),
147 // FIXME: Flags are the wrong mechanism for user preferences.
148 // We should probably read a dotfile or similar.
149 opt
<bool> AllScopesCompletion
{
150 "all-scopes-completion",
152 desc("If set to true, code completion will include index symbols that are "
153 "not defined in the scopes (e.g. "
154 "namespaces) visible from the code completion point. Such completions "
155 "can insert scope qualifiers"),
159 opt
<bool> ShowOrigins
{
162 desc("Show origins of completion items"),
163 init(CodeCompleteOptions().ShowOrigins
),
167 opt
<bool> EnableBackgroundIndex
{
170 desc("Index project code in the background and persist index on disk."),
174 opt
<llvm::ThreadPriority
> BackgroundIndexPriority
{
175 "background-index-priority",
177 desc("Thread priority for building the background index. "
178 "The effect of this flag is OS-specific."),
179 values(clEnumValN(llvm::ThreadPriority::Background
, "background",
180 "Minimum priority, runs on idle CPUs. "
181 "May leave 'performance' cores unused."),
182 clEnumValN(llvm::ThreadPriority::Low
, "low",
183 "Reduced priority compared to interactive work."),
184 clEnumValN(llvm::ThreadPriority::Default
, "normal",
185 "Same priority as other clangd work.")),
186 init(llvm::ThreadPriority::Low
),
189 opt
<bool> EnableClangTidy
{
192 desc("Enable clang-tidy diagnostics"),
196 opt
<CodeCompleteOptions::CodeCompletionParse
> CodeCompletionParse
{
199 desc("Whether the clang-parser is used for code-completion"),
200 values(clEnumValN(CodeCompleteOptions::AlwaysParse
, "always",
201 "Block until the parser can be used"),
202 clEnumValN(CodeCompleteOptions::ParseIfReady
, "auto",
203 "Use text-based completion if the parser "
205 clEnumValN(CodeCompleteOptions::NeverParse
, "never",
206 "Always used text-based completion")),
207 init(CodeCompleteOptions().RunParser
),
211 opt
<CodeCompleteOptions::CodeCompletionRankingModel
> RankingModel
{
214 desc("Model to use to rank code-completion items"),
215 values(clEnumValN(CodeCompleteOptions::Heuristics
, "heuristics",
216 "Use heuristics to rank code completion items"),
217 clEnumValN(CodeCompleteOptions::DecisionForest
, "decision_forest",
218 "Use Decision Forest model to rank completion items")),
219 init(CodeCompleteOptions().RankingModel
),
223 // FIXME: also support "plain" style where signatures are always omitted.
224 enum CompletionStyleFlag
{ Detailed
, Bundled
};
225 opt
<CompletionStyleFlag
> CompletionStyle
{
228 desc("Granularity of code completion suggestions"),
229 values(clEnumValN(Detailed
, "detailed",
230 "One completion item for each semantically distinct "
231 "completion, with full type information"),
232 clEnumValN(Bundled
, "bundled",
233 "Similar completion items (e.g. function overloads) are "
234 "combined. Type information shown where possible")),
237 opt
<std::string
> FallbackStyle
{
240 desc("clang-format style to apply by default when "
241 "no .clang-format file is found"),
242 init(clang::format::DefaultFallbackStyle
),
245 opt
<int> EnableFunctionArgSnippets
{
246 "function-arg-placeholders",
248 desc("When disabled (0), completions contain only parentheses for "
249 "function calls. When enabled (1), completions also contain "
250 "placeholders for method parameters"),
254 opt
<CodeCompleteOptions::IncludeInsertion
> HeaderInsertion
{
257 desc("Add #include directives when accepting code completions"),
258 init(CodeCompleteOptions().InsertIncludes
),
260 clEnumValN(CodeCompleteOptions::IWYU
, "iwyu",
261 "Include what you use. "
262 "Insert the owning header for top-level symbols, unless the "
263 "header is already directly included or the symbol is "
266 CodeCompleteOptions::NeverInsert
, "never",
267 "Never insert #include directives as part of code completion")),
270 opt
<bool> ImportInsertions
{
273 desc("If header insertion is enabled, add #import directives when "
274 "accepting code completions or fixing includes in Objective-C code"),
275 init(CodeCompleteOptions().ImportInsertions
),
278 opt
<bool> HeaderInsertionDecorators
{
279 "header-insertion-decorators",
281 desc("Prepend a circular dot or space before the completion "
282 "label, depending on whether "
283 "an include line will be inserted or not"),
287 opt
<bool> HiddenFeatures
{
290 desc("Enable hidden features mostly useful to clangd developers"),
295 opt
<bool> IncludeIneligibleResults
{
296 "include-ineligible-results",
298 desc("Include ineligible completion results (e.g. private members)"),
299 init(CodeCompleteOptions().IncludeIneligibleResults
),
303 RetiredFlag
<bool> EnableIndex("index");
304 RetiredFlag
<bool> SuggestMissingIncludes("suggest-missing-includes");
305 RetiredFlag
<bool> RecoveryAST("recovery-ast");
306 RetiredFlag
<bool> RecoveryASTType("recovery-ast-type");
307 RetiredFlag
<bool> AsyncPreamble("async-preamble");
308 RetiredFlag
<bool> CollectMainFileRefs("collect-main-file-refs");
309 RetiredFlag
<bool> CrossFileRename("cross-file-rename");
310 RetiredFlag
<std::string
> ClangTidyChecks("clang-tidy-checks");
311 RetiredFlag
<bool> InlayHints("inlay-hints");
312 RetiredFlag
<bool> FoldingRanges("folding-ranges");
313 RetiredFlag
<bool> IncludeCleanerStdlib("include-cleaner-stdlib");
315 opt
<int> LimitResults
{
318 desc("Limit the number of results returned by clangd. "
319 "0 means no limit (default=100)"),
323 opt
<int> ReferencesLimit
{
326 desc("Limit the number of references returned by clangd. "
327 "0 means no limit (default=1000)"),
331 opt
<int> RenameFileLimit
{
334 desc("Limit the number of files to be affected by symbol renaming. "
335 "0 means no limit (default=50)"),
339 list
<std::string
> TweakList
{
342 desc("Specify a list of Tweaks to enable (only for clangd developers)."),
347 opt
<unsigned> WorkerThreadsCount
{
350 desc("Number of async workers used by clangd. Background index also "
351 "uses this many workers."),
352 init(getDefaultAsyncThreadsCount()),
359 "Index file to build the static index. The file must have been created "
360 "by a compatible clangd-indexer\n"
361 "WARNING: This option is experimental only, and will be removed "
362 "eventually. Don't rely on it"),
370 desc("Abbreviation for -input-style=delimited -pretty -sync "
371 "-enable-test-scheme -enable-config=0 -log=verbose -crash-pragmas. "
372 "Also sets config options: Index.StandardLibrary=false. "
373 "Intended to simplify lit tests"),
378 opt
<bool> CrashPragmas
{
381 desc("Respect `#pragma clang __debug crash` and friends."),
389 desc("Parse one file in isolation instead of acting as a language server. "
390 "Useful to investigate/reproduce crashes or configuration problems. "
391 "With --check=<filename>, attempts to parse a particular file."),
396 enum PCHStorageFlag
{ Disk
, Memory
};
397 opt
<PCHStorageFlag
> PCHStorage
{
400 desc("Storing PCHs in memory increases memory usages, but may "
401 "improve performance"),
403 clEnumValN(PCHStorageFlag::Disk
, "disk", "store PCHs on disk"),
404 clEnumValN(PCHStorageFlag::Memory
, "memory", "store PCHs in memory")),
405 init(PCHStorageFlag::Disk
),
411 desc("Handle client requests on main thread. Background index still uses "
417 opt
<JSONStreamStyle
> InputStyle
{
420 desc("Input JSON stream encoding"),
422 clEnumValN(JSONStreamStyle::Standard
, "standard", "usual LSP protocol"),
423 clEnumValN(JSONStreamStyle::Delimited
, "delimited",
424 "messages delimited by --- lines, with # comment support")),
425 init(JSONStreamStyle::Standard
),
429 opt
<bool> EnableTestScheme
{
430 "enable-test-uri-scheme",
432 desc("Enable 'test:' URI scheme. Only use in lit tests"),
437 opt
<std::string
> PathMappingsArg
{
441 "Translates between client paths (as seen by a remote editor) and "
442 "server paths (where clangd sees files on disk). "
443 "Comma separated list of '<client_path>=<server_path>' pairs, the "
444 "first entry matching a given path is used. "
445 "e.g. /home/project/incl=/opt/include,/home/project=/workarea/project"),
449 opt
<Path
> InputMirrorFile
{
452 desc("Mirror all LSP input to the specified file. Useful for debugging"),
457 opt
<Logger::Level
> LogLevel
{
460 desc("Verbosity of log messages written to stderr"),
461 values(clEnumValN(Logger::Error
, "error", "Error messages only"),
462 clEnumValN(Logger::Info
, "info", "High level execution tracing"),
463 clEnumValN(Logger::Debug
, "verbose", "Low level details")),
467 opt
<OffsetEncoding
> ForceOffsetEncoding
{
470 desc("Force the offsetEncoding used for character positions. "
471 "This bypasses negotiation via client capabilities"),
473 clEnumValN(OffsetEncoding::UTF8
, "utf-8", "Offsets are in UTF-8 bytes"),
474 clEnumValN(OffsetEncoding::UTF16
, "utf-16",
475 "Offsets are in UTF-16 code units"),
476 clEnumValN(OffsetEncoding::UTF32
, "utf-32",
477 "Offsets are in unicode codepoints")),
478 init(OffsetEncoding::UnsupportedEncoding
),
481 opt
<bool> PrettyPrint
{
484 desc("Pretty-print JSON output"),
488 opt
<bool> EnableConfig
{
492 "Read user and project configuration from YAML files.\n"
493 "Project config is from a .clangd file in the project directory.\n"
494 "User config is from clangd/config.yaml in the following directories:\n"
495 "\tWindows: %USERPROFILE%\\AppData\\Local\n"
496 "\tMac OS: ~/Library/Preferences/\n"
497 "\tOthers: $XDG_CONFIG_HOME, usually ~/.config\n"
498 "Configuration is documented at https://clangd.llvm.org/config.html"),
502 opt
<bool> UseDirtyHeaders
{"use-dirty-headers", cat(Misc
),
503 desc("Use files open in the editor when parsing "
504 "headers instead of reading from the disk"),
506 init(ClangdServer::Options().UseDirtyHeaders
)};
508 opt
<bool> PreambleParseForwardingFunctions
{
509 "parse-forwarding-functions",
511 desc("Parse all emplace-like functions in included headers"),
513 init(ParseOptions().PreambleParseForwardingFunctions
),
516 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
517 opt
<bool> EnableMallocTrim
{
520 desc("Release memory periodically via malloc_trim(3)."),
524 std::function
<void()> getMemoryCleanupFunction() {
525 if (!EnableMallocTrim
)
527 // Leave a few MB at the top of the heap: it is insignificant
528 // and will most likely be needed by the main thread
529 constexpr size_t MallocTrimPad
= 20'000'000;
531 if (malloc_trim(MallocTrimPad
))
532 vlog("Released memory via malloc_trim");
536 std::function
<void()> getMemoryCleanupFunction() { return nullptr; }
539 #if CLANGD_ENABLE_REMOTE
540 opt
<std::string
> RemoteIndexAddress
{
541 "remote-index-address",
543 desc("Address of the remote index server"),
546 // FIXME(kirillbobyrev): Should this be the location of compile_commands.json?
547 opt
<std::string
> ProjectRoot
{
550 desc("Path to the project root. Requires remote-index-address to be set."),
554 opt
<bool> ExperimentalModulesSupport
{
555 "experimental-modules-support",
557 desc("Experimental support for standard c++ modules"),
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
{
567 llvm::Expected
<std::string
>
568 getAbsolutePath(llvm::StringRef
/*Authority*/, llvm::StringRef Body
,
569 llvm::StringRef
/*HintPath*/) const override
{
570 using namespace llvm::sys
;
571 // Still require "/" in body to mimic file scheme, as we want lengths of an
572 // equivalent URI in both schemes to be the same.
573 if (!Body
.starts_with("/"))
575 "Expect URI body to be an absolute path starting with '/': {0}",
577 Body
= Body
.ltrim('/');
578 llvm::SmallString
<16> Path(Body
);
580 fs::make_absolute(TestScheme::TestDir
, Path
);
581 return std::string(Path
);
585 uriFromAbsolutePath(llvm::StringRef AbsolutePath
) const override
{
586 llvm::StringRef Body
= AbsolutePath
;
587 if (!Body
.consume_front(TestScheme::TestDir
))
588 return error("Path {0} doesn't start with root {1}", AbsolutePath
,
591 return URI("test", /*Authority=*/"",
592 llvm::sys::path::convert_to_slash(Body
));
596 const static char TestDir
[];
600 const char TestScheme::TestDir
[] = "C:\\clangd-test";
602 const char TestScheme::TestDir
[] = "/clangd-test";
605 std::unique_ptr
<SymbolIndex
>
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
:
613 case Config::ExternalIndexSpec::Server
:
614 RemoteIndexUsed
.record(1, External
.Location
);
615 log("Associating {0} with remote index at {1}.", External
.MountPoint
,
617 return remote::getClient(External
.Location
, External
.MountPoint
);
618 case Config::ExternalIndexSpec::File
:
619 log("Associating {0} with monolithic index at {1}.", External
.MountPoint
,
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
));
628 Tasks
->runAsync("Load-index:" + External
.Location
,
629 std::move(IndexLoadTask
));
633 return std::move(NewIndex
);
635 llvm_unreachable("Invalid ExternalIndexKind.");
638 class FlagsConfigProvider
: public config::Provider
{
640 config::CompiledFragment Frag
;
642 std::vector
<config::CompiledFragment
>
643 getFragments(const config::Params
&,
644 config::DiagnosticCallback
) const override
{
649 FlagsConfigProvider() {
650 std::optional
<Config::CDBSearchSpec
> CDBSearch
;
651 std::optional
<Config::ExternalIndexSpec
> IndexSpec
;
652 std::optional
<Config::BackgroundPolicy
> BGPolicy
;
653 std::optional
<Config::ArgumentListsPolicy
> ArgumentLists
;
655 // If --compile-commands-dir arg was invoked, check value and override
657 if (!CompileCommandsDir
.empty()) {
658 if (llvm::sys::fs::exists(CompileCommandsDir
)) {
659 // We support passing both relative and absolute paths to the
660 // --compile-commands-dir argument, but we assume the path is absolute
661 // in the rest of clangd so we make sure the path is absolute before
663 llvm::SmallString
<128> Path(CompileCommandsDir
);
664 if (std::error_code EC
= llvm::sys::fs::make_absolute(Path
)) {
665 elog("Error while converting the relative path specified by "
666 "--compile-commands-dir to an absolute path: {0}. The argument "
670 CDBSearch
= {Config::CDBSearchSpec::FixedDir
, Path
.str().str()};
673 elog("Path specified by --compile-commands-dir does not exist. The "
674 "argument will be ignored.");
677 if (!IndexFile
.empty()) {
678 Config::ExternalIndexSpec Spec
;
679 Spec
.Kind
= Spec
.File
;
680 Spec
.Location
= IndexFile
;
681 IndexSpec
= std::move(Spec
);
683 #if CLANGD_ENABLE_REMOTE
684 if (!RemoteIndexAddress
.empty()) {
685 assert(!ProjectRoot
.empty() && IndexFile
.empty());
686 Config::ExternalIndexSpec Spec
;
687 Spec
.Kind
= Spec
.Server
;
688 Spec
.Location
= RemoteIndexAddress
;
689 Spec
.MountPoint
= ProjectRoot
;
690 IndexSpec
= std::move(Spec
);
691 BGPolicy
= Config::BackgroundPolicy::Skip
;
694 if (!EnableBackgroundIndex
) {
695 BGPolicy
= Config::BackgroundPolicy::Skip
;
698 if (EnableFunctionArgSnippets
>= 0) {
699 ArgumentLists
= EnableFunctionArgSnippets
700 ? Config::ArgumentListsPolicy::FullPlaceholders
701 : Config::ArgumentListsPolicy::Delimiters
;
704 Frag
= [=](const config::Params
&, Config
&C
) {
706 C
.CompileFlags
.CDBSearch
= *CDBSearch
;
708 C
.Index
.External
= *IndexSpec
;
710 C
.Index
.Background
= *BGPolicy
;
712 C
.Completion
.ArgumentLists
= *ArgumentLists
;
713 if (AllScopesCompletion
.getNumOccurrences())
714 C
.Completion
.AllScopes
= AllScopesCompletion
;
717 C
.Index
.StandardLibrary
= false;
724 enum class ErrorResultCode
: int {
725 NoShutdownRequest
= 1,
726 CantRunAsXPCService
= 2,
730 int clangdMain(int argc
, char *argv
[]) {
731 // Clang could run on the main thread. e.g., when the flag '-check' or '-sync'
733 clang::noteBottomOfStack();
734 llvm::InitLLVM
X(argc
, argv
);
735 llvm::InitializeAllTargetInfos();
736 llvm::sys::AddSignalHandler(
738 ThreadCrashReporter::runCrashHandlers();
739 // Ensure ThreadCrashReporter and PrintStackTrace output is visible.
740 llvm::errs().flush();
743 llvm::sys::SetInterruptFunction(&requestShutdown
);
744 llvm::cl::SetVersionPrinter([](llvm::raw_ostream
&OS
) {
745 OS
<< versionString() << "\n"
746 << "Features: " << featureString() << "\n"
747 << "Platform: " << platformString() << "\n";
749 const char *FlagsEnvVar
= "CLANGD_FLAGS";
750 const char *Overview
=
751 R
"(clangd is a language server that provides IDE-like features to editors.
753 It should be used via an editor plugin rather than invoked directly. For more information, see:
754 https://clangd.llvm.org/
755 https://microsoft.github.io/language-server-protocol/
757 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
759 llvm::cl::HideUnrelatedOptions(ClangdCategories
);
760 llvm::cl::ParseCommandLineOptions(argc
, argv
, Overview
,
761 /*Errs=*/nullptr, FlagsEnvVar
);
763 if (!Sync
.getNumOccurrences())
765 if (!CrashPragmas
.getNumOccurrences())
767 InputStyle
= JSONStreamStyle::Delimited
;
768 LogLevel
= Logger::Verbose
;
770 // Disable config system by default to avoid external reads.
771 if (!EnableConfig
.getNumOccurrences())
772 EnableConfig
= false;
773 // Disable background index on lit tests by default to prevent disk writes.
774 if (!EnableBackgroundIndex
.getNumOccurrences())
775 EnableBackgroundIndex
= false;
776 // Ensure background index makes progress.
777 else if (EnableBackgroundIndex
)
778 BackgroundQueue::preventThreadStarvationInTests();
780 if (Test
|| EnableTestScheme
) {
781 static URISchemeRegistry::Add
<TestScheme
> X(
782 "test", "Test scheme for clangd lit tests.");
785 allowCrashPragmasForTest();
787 if (!Sync
&& WorkerThreadsCount
== 0) {
788 llvm::errs() << "A number of worker threads cannot be 0. Did you mean to "
794 if (WorkerThreadsCount
.getNumOccurrences())
795 llvm::errs() << "Ignoring -j because -sync is set.\n";
796 WorkerThreadsCount
= 0;
798 if (FallbackStyle
.getNumOccurrences())
799 clang::format::DefaultFallbackStyle
= FallbackStyle
.c_str();
801 // Validate command line arguments.
802 std::optional
<llvm::raw_fd_ostream
> InputMirrorStream
;
803 if (!InputMirrorFile
.empty()) {
805 InputMirrorStream
.emplace(InputMirrorFile
, /*ref*/ EC
,
806 llvm::sys::fs::FA_Read
| llvm::sys::fs::FA_Write
);
808 InputMirrorStream
.reset();
809 llvm::errs() << "Error while opening an input mirror file: "
812 InputMirrorStream
->SetUnbuffered();
816 #if !CLANGD_DECISION_FOREST
817 if (RankingModel
== clangd::CodeCompleteOptions::DecisionForest
) {
818 llvm::errs() << "Clangd was compiled without decision forest support.\n";
823 // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a
824 // trace flag in your editor's config is annoying, launching with
825 // `CLANGD_TRACE=trace.json vim` is easier.
826 std::optional
<llvm::raw_fd_ostream
> TracerStream
;
827 std::unique_ptr
<trace::EventTracer
> Tracer
;
828 const char *JSONTraceFile
= getenv("CLANGD_TRACE");
829 const char *MetricsCSVFile
= getenv("CLANGD_METRICS");
830 const char *TracerFile
= JSONTraceFile
? JSONTraceFile
: MetricsCSVFile
;
833 TracerStream
.emplace(TracerFile
, /*ref*/ EC
,
834 llvm::sys::fs::FA_Read
| llvm::sys::fs::FA_Write
);
836 TracerStream
.reset();
837 llvm::errs() << "Error while opening trace file " << TracerFile
<< ": "
840 Tracer
= (TracerFile
== JSONTraceFile
)
841 ? trace::createJSONTracer(*TracerStream
, PrettyPrint
)
842 : trace::createCSVMetricTracer(*TracerStream
);
846 std::optional
<trace::Session
> TracingSession
;
848 TracingSession
.emplace(*Tracer
);
850 // If a user ran `clangd` in a terminal without redirecting anything,
851 // it's somewhat likely they're confused about how to use clangd.
852 // Show them the help overview, which explains.
853 if (llvm::outs().is_displayed() && llvm::errs().is_displayed() &&
854 !CheckFile
.getNumOccurrences())
855 llvm::errs() << Overview
<< "\n";
856 // Use buffered stream to stderr (we still flush each log message). Unbuffered
857 // stream can cause significant (non-deterministic) latency for the logger.
858 llvm::errs().SetBuffered();
859 StreamLogger
Logger(llvm::errs(), LogLevel
);
860 LoggingSession
LoggingSession(Logger
);
861 // Write some initial logs before we start doing any real work.
862 log("{0}", versionString());
863 log("Features: {0}", featureString());
864 log("PID: {0}", llvm::sys::Process::getProcessId());
866 SmallString
<128> CWD
;
867 if (auto Err
= llvm::sys::fs::current_path(CWD
))
868 log("Working directory unknown: {0}", Err
.message());
870 log("Working directory: {0}", CWD
);
872 for (int I
= 0; I
< argc
; ++I
)
873 log("argv[{0}]: {1}", I
, argv
[I
]);
874 if (auto EnvFlags
= llvm::sys::Process::GetEnv(FlagsEnvVar
))
875 log("{0}: {1}", FlagsEnvVar
, *EnvFlags
);
877 ClangdLSPServer::Options Opts
;
878 Opts
.UseDirBasedCDB
= (CompileArgsFrom
== FilesystemCompileArgs
);
879 Opts
.EnableExperimentalModulesSupport
= ExperimentalModulesSupport
;
881 switch (PCHStorage
) {
882 case PCHStorageFlag::Memory
:
883 Opts
.StorePreamblesInMemory
= true;
885 case PCHStorageFlag::Disk
:
886 Opts
.StorePreamblesInMemory
= false;
889 if (!ResourceDir
.empty())
890 Opts
.ResourceDir
= ResourceDir
;
891 Opts
.BuildDynamicSymbolIndex
= true;
892 std::vector
<std::unique_ptr
<SymbolIndex
>> IdxStack
;
893 #if CLANGD_ENABLE_REMOTE
894 if (RemoteIndexAddress
.empty() != ProjectRoot
.empty()) {
895 llvm::errs() << "remote-index-address and project-path have to be "
896 "specified at the same time.";
899 if (!RemoteIndexAddress
.empty()) {
900 if (IndexFile
.empty()) {
901 log("Connecting to remote index at {0}", RemoteIndexAddress
);
903 elog("When enabling remote index, IndexFile should not be specified. "
904 "Only one can be used at time. Remote index will ignored.");
908 Opts
.BackgroundIndex
= EnableBackgroundIndex
;
909 Opts
.BackgroundIndexPriority
= BackgroundIndexPriority
;
910 Opts
.ReferencesLimit
= ReferencesLimit
;
911 Opts
.Rename
.LimitFiles
= RenameFileLimit
;
912 auto PAI
= createProjectAwareIndex(loadExternalIndex
, Sync
);
913 Opts
.StaticIndex
= PAI
.get();
914 Opts
.AsyncThreadsCount
= WorkerThreadsCount
;
915 Opts
.MemoryCleanup
= getMemoryCleanupFunction();
917 Opts
.CodeComplete
.IncludeIneligibleResults
= IncludeIneligibleResults
;
918 Opts
.CodeComplete
.Limit
= LimitResults
;
919 if (CompletionStyle
.getNumOccurrences())
920 Opts
.CodeComplete
.BundleOverloads
= CompletionStyle
!= Detailed
;
921 Opts
.CodeComplete
.ShowOrigins
= ShowOrigins
;
922 Opts
.CodeComplete
.InsertIncludes
= HeaderInsertion
;
923 Opts
.CodeComplete
.ImportInsertions
= ImportInsertions
;
924 if (!HeaderInsertionDecorators
) {
925 Opts
.CodeComplete
.IncludeIndicator
.Insert
.clear();
926 Opts
.CodeComplete
.IncludeIndicator
.NoInsert
.clear();
928 Opts
.CodeComplete
.RunParser
= CodeCompletionParse
;
929 Opts
.CodeComplete
.RankingModel
= RankingModel
;
930 // FIXME: If we're using C++20 modules, force the lookup process to load
931 // external decls, since currently the index doesn't support C++20 modules.
932 Opts
.CodeComplete
.ForceLoadPreamble
= ExperimentalModulesSupport
;
934 RealThreadsafeFS TFS
;
935 std::vector
<std::unique_ptr
<config::Provider
>> ProviderStack
;
936 std::unique_ptr
<config::Provider
> Config
;
938 ProviderStack
.push_back(
939 config::Provider::fromAncestorRelativeYAMLFiles(".clangd", TFS
));
940 llvm::SmallString
<256> UserConfig
;
941 if (llvm::sys::path::user_config_directory(UserConfig
)) {
942 llvm::sys::path::append(UserConfig
, "clangd", "config.yaml");
943 vlog("User config file is {0}", UserConfig
);
944 ProviderStack
.push_back(config::Provider::fromYAMLFile(
945 UserConfig
, /*Directory=*/"", TFS
, /*Trusted=*/true));
947 elog("Couldn't determine user config file, not loading");
950 ProviderStack
.push_back(std::make_unique
<FlagsConfigProvider
>());
951 std::vector
<const config::Provider
*> ProviderPointers
;
952 for (const auto &P
: ProviderStack
)
953 ProviderPointers
.push_back(P
.get());
954 Config
= config::Provider::combine(std::move(ProviderPointers
));
955 Opts
.ConfigProvider
= Config
.get();
957 // Create an empty clang-tidy option.
958 TidyProvider ClangTidyOptProvider
;
959 if (EnableClangTidy
) {
960 std::vector
<TidyProvider
> Providers
;
961 Providers
.reserve(4 + EnableConfig
);
962 Providers
.push_back(provideEnvironment());
963 Providers
.push_back(provideClangTidyFiles(TFS
));
965 Providers
.push_back(provideClangdConfig());
966 Providers
.push_back(provideDefaultChecks());
967 Providers
.push_back(disableUnusableChecks());
968 ClangTidyOptProvider
= combine(std::move(Providers
));
969 Opts
.ClangTidyProvider
= ClangTidyOptProvider
;
971 Opts
.UseDirtyHeaders
= UseDirtyHeaders
;
972 Opts
.PreambleParseForwardingFunctions
= PreambleParseForwardingFunctions
;
973 Opts
.ImportInsertions
= ImportInsertions
;
974 Opts
.QueryDriverGlobs
= std::move(QueryDriverGlobs
);
975 Opts
.TweakFilter
= [&](const Tweak
&T
) {
976 if (T
.hidden() && !HiddenFeatures
)
978 if (TweakList
.getNumOccurrences())
979 return llvm::is_contained(TweakList
, T
.id());
982 if (ForceOffsetEncoding
!= OffsetEncoding::UnsupportedEncoding
)
983 Opts
.Encoding
= ForceOffsetEncoding
;
985 if (CheckFile
.getNumOccurrences()) {
986 llvm::SmallString
<256> Path
;
988 llvm::sys::fs::real_path(CheckFile
, Path
, /*expand_tilde=*/true)) {
989 elog("Failed to resolve path {0}: {1}", CheckFile
, Error
.message());
992 log("Entering check mode (no LSP server)");
993 return check(Path
, TFS
, Opts
)
995 : static_cast<int>(ErrorResultCode::CheckFailed
);
998 // Initialize and run ClangdLSPServer.
999 // Change stdin to binary to not lose \r\n on windows.
1000 llvm::sys::ChangeStdinToBinary();
1001 std::unique_ptr
<Transport
> TransportLayer
;
1002 if (getenv("CLANGD_AS_XPC_SERVICE")) {
1003 #if CLANGD_BUILD_XPC
1004 log("Starting LSP over XPC service");
1005 TransportLayer
= newXPCTransport();
1007 llvm::errs() << "This clangd binary wasn't built with XPC support.\n";
1008 return static_cast<int>(ErrorResultCode::CantRunAsXPCService
);
1011 log("Starting LSP over stdin/stdout");
1012 TransportLayer
= newJSONTransport(
1013 stdin
, llvm::outs(), InputMirrorStream
? &*InputMirrorStream
: nullptr,
1014 PrettyPrint
, InputStyle
);
1016 if (!PathMappingsArg
.empty()) {
1017 auto Mappings
= parsePathMappings(PathMappingsArg
);
1019 elog("Invalid -path-mappings: {0}", Mappings
.takeError());
1022 TransportLayer
= createPathMappingTransport(std::move(TransportLayer
),
1023 std::move(*Mappings
));
1026 ClangdLSPServer
LSPServer(*TransportLayer
, TFS
, Opts
);
1027 llvm::set_thread_name("clangd.main");
1028 int ExitCode
= LSPServer
.run()
1030 : static_cast<int>(ErrorResultCode::NoShutdownRequest
);
1031 log("LSP finished, exiting with status {0}", ExitCode
);
1033 // There may still be lingering background threads (e.g. slow requests
1034 // whose results will be dropped, background index shutting down).
1036 // These should terminate quickly, and ~ClangdLSPServer blocks on them.
1037 // However if a bug causes them to run forever, we want to ensure the process
1038 // eventually exits. As clangd isn't directly user-facing, an editor can
1039 // "leak" clangd processes. Crashing in this case contains the damage.
1040 abortAfterTimeout(std::chrono::minutes(5));
1045 } // namespace clangd
1046 } // namespace clang