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
<bool> EnableFunctionArgSnippets
{
246 "function-arg-placeholders",
248 desc("When disabled, completions contain only parentheses for "
249 "function calls. When enabled, completions also contain "
250 "placeholders for method parameters"),
251 init(CodeCompleteOptions().EnableFunctionArgSnippets
),
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
;
654 // If --compile-commands-dir arg was invoked, check value and override
656 if (!CompileCommandsDir
.empty()) {
657 if (llvm::sys::fs::exists(CompileCommandsDir
)) {
658 // We support passing both relative and absolute paths to the
659 // --compile-commands-dir argument, but we assume the path is absolute
660 // in the rest of clangd so we make sure the path is absolute before
662 llvm::SmallString
<128> Path(CompileCommandsDir
);
663 if (std::error_code EC
= llvm::sys::fs::make_absolute(Path
)) {
664 elog("Error while converting the relative path specified by "
665 "--compile-commands-dir to an absolute path: {0}. The argument "
669 CDBSearch
= {Config::CDBSearchSpec::FixedDir
, Path
.str().str()};
672 elog("Path specified by --compile-commands-dir does not exist. The "
673 "argument will be ignored.");
676 if (!IndexFile
.empty()) {
677 Config::ExternalIndexSpec Spec
;
678 Spec
.Kind
= Spec
.File
;
679 Spec
.Location
= IndexFile
;
680 IndexSpec
= std::move(Spec
);
682 #if CLANGD_ENABLE_REMOTE
683 if (!RemoteIndexAddress
.empty()) {
684 assert(!ProjectRoot
.empty() && IndexFile
.empty());
685 Config::ExternalIndexSpec Spec
;
686 Spec
.Kind
= Spec
.Server
;
687 Spec
.Location
= RemoteIndexAddress
;
688 Spec
.MountPoint
= ProjectRoot
;
689 IndexSpec
= std::move(Spec
);
690 BGPolicy
= Config::BackgroundPolicy::Skip
;
693 if (!EnableBackgroundIndex
) {
694 BGPolicy
= Config::BackgroundPolicy::Skip
;
697 Frag
= [=](const config::Params
&, Config
&C
) {
699 C
.CompileFlags
.CDBSearch
= *CDBSearch
;
701 C
.Index
.External
= *IndexSpec
;
703 C
.Index
.Background
= *BGPolicy
;
704 if (AllScopesCompletion
.getNumOccurrences())
705 C
.Completion
.AllScopes
= AllScopesCompletion
;
708 C
.Index
.StandardLibrary
= false;
715 enum class ErrorResultCode
: int {
716 NoShutdownRequest
= 1,
717 CantRunAsXPCService
= 2,
721 int clangdMain(int argc
, char *argv
[]) {
722 // Clang could run on the main thread. e.g., when the flag '-check' or '-sync'
724 clang::noteBottomOfStack();
725 llvm::InitLLVM
X(argc
, argv
);
726 llvm::InitializeAllTargetInfos();
727 llvm::sys::AddSignalHandler(
729 ThreadCrashReporter::runCrashHandlers();
730 // Ensure ThreadCrashReporter and PrintStackTrace output is visible.
731 llvm::errs().flush();
734 llvm::sys::SetInterruptFunction(&requestShutdown
);
735 llvm::cl::SetVersionPrinter([](llvm::raw_ostream
&OS
) {
736 OS
<< versionString() << "\n"
737 << "Features: " << featureString() << "\n"
738 << "Platform: " << platformString() << "\n";
740 const char *FlagsEnvVar
= "CLANGD_FLAGS";
741 const char *Overview
=
742 R
"(clangd is a language server that provides IDE-like features to editors.
744 It should be used via an editor plugin rather than invoked directly. For more information, see:
745 https://clangd.llvm.org/
746 https://microsoft.github.io/language-server-protocol/
748 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
750 llvm::cl::HideUnrelatedOptions(ClangdCategories
);
751 llvm::cl::ParseCommandLineOptions(argc
, argv
, Overview
,
752 /*Errs=*/nullptr, FlagsEnvVar
);
754 if (!Sync
.getNumOccurrences())
756 if (!CrashPragmas
.getNumOccurrences())
758 InputStyle
= JSONStreamStyle::Delimited
;
759 LogLevel
= Logger::Verbose
;
761 // Disable config system by default to avoid external reads.
762 if (!EnableConfig
.getNumOccurrences())
763 EnableConfig
= false;
764 // Disable background index on lit tests by default to prevent disk writes.
765 if (!EnableBackgroundIndex
.getNumOccurrences())
766 EnableBackgroundIndex
= false;
767 // Ensure background index makes progress.
768 else if (EnableBackgroundIndex
)
769 BackgroundQueue::preventThreadStarvationInTests();
771 if (Test
|| EnableTestScheme
) {
772 static URISchemeRegistry::Add
<TestScheme
> X(
773 "test", "Test scheme for clangd lit tests.");
776 allowCrashPragmasForTest();
778 if (!Sync
&& WorkerThreadsCount
== 0) {
779 llvm::errs() << "A number of worker threads cannot be 0. Did you mean to "
785 if (WorkerThreadsCount
.getNumOccurrences())
786 llvm::errs() << "Ignoring -j because -sync is set.\n";
787 WorkerThreadsCount
= 0;
789 if (FallbackStyle
.getNumOccurrences())
790 clang::format::DefaultFallbackStyle
= FallbackStyle
.c_str();
792 // Validate command line arguments.
793 std::optional
<llvm::raw_fd_ostream
> InputMirrorStream
;
794 if (!InputMirrorFile
.empty()) {
796 InputMirrorStream
.emplace(InputMirrorFile
, /*ref*/ EC
,
797 llvm::sys::fs::FA_Read
| llvm::sys::fs::FA_Write
);
799 InputMirrorStream
.reset();
800 llvm::errs() << "Error while opening an input mirror file: "
803 InputMirrorStream
->SetUnbuffered();
807 #if !CLANGD_DECISION_FOREST
808 if (RankingModel
== clangd::CodeCompleteOptions::DecisionForest
) {
809 llvm::errs() << "Clangd was compiled without decision forest support.\n";
814 // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a
815 // trace flag in your editor's config is annoying, launching with
816 // `CLANGD_TRACE=trace.json vim` is easier.
817 std::optional
<llvm::raw_fd_ostream
> TracerStream
;
818 std::unique_ptr
<trace::EventTracer
> Tracer
;
819 const char *JSONTraceFile
= getenv("CLANGD_TRACE");
820 const char *MetricsCSVFile
= getenv("CLANGD_METRICS");
821 const char *TracerFile
= JSONTraceFile
? JSONTraceFile
: MetricsCSVFile
;
824 TracerStream
.emplace(TracerFile
, /*ref*/ EC
,
825 llvm::sys::fs::FA_Read
| llvm::sys::fs::FA_Write
);
827 TracerStream
.reset();
828 llvm::errs() << "Error while opening trace file " << TracerFile
<< ": "
831 Tracer
= (TracerFile
== JSONTraceFile
)
832 ? trace::createJSONTracer(*TracerStream
, PrettyPrint
)
833 : trace::createCSVMetricTracer(*TracerStream
);
837 std::optional
<trace::Session
> TracingSession
;
839 TracingSession
.emplace(*Tracer
);
841 // If a user ran `clangd` in a terminal without redirecting anything,
842 // it's somewhat likely they're confused about how to use clangd.
843 // Show them the help overview, which explains.
844 if (llvm::outs().is_displayed() && llvm::errs().is_displayed() &&
845 !CheckFile
.getNumOccurrences())
846 llvm::errs() << Overview
<< "\n";
847 // Use buffered stream to stderr (we still flush each log message). Unbuffered
848 // stream can cause significant (non-deterministic) latency for the logger.
849 llvm::errs().SetBuffered();
850 StreamLogger
Logger(llvm::errs(), LogLevel
);
851 LoggingSession
LoggingSession(Logger
);
852 // Write some initial logs before we start doing any real work.
853 log("{0}", versionString());
854 log("Features: {0}", featureString());
855 log("PID: {0}", llvm::sys::Process::getProcessId());
857 SmallString
<128> CWD
;
858 if (auto Err
= llvm::sys::fs::current_path(CWD
))
859 log("Working directory unknown: {0}", Err
.message());
861 log("Working directory: {0}", CWD
);
863 for (int I
= 0; I
< argc
; ++I
)
864 log("argv[{0}]: {1}", I
, argv
[I
]);
865 if (auto EnvFlags
= llvm::sys::Process::GetEnv(FlagsEnvVar
))
866 log("{0}: {1}", FlagsEnvVar
, *EnvFlags
);
868 ClangdLSPServer::Options Opts
;
869 Opts
.UseDirBasedCDB
= (CompileArgsFrom
== FilesystemCompileArgs
);
870 Opts
.EnableExperimentalModulesSupport
= ExperimentalModulesSupport
;
872 switch (PCHStorage
) {
873 case PCHStorageFlag::Memory
:
874 Opts
.StorePreamblesInMemory
= true;
876 case PCHStorageFlag::Disk
:
877 Opts
.StorePreamblesInMemory
= false;
880 if (!ResourceDir
.empty())
881 Opts
.ResourceDir
= ResourceDir
;
882 Opts
.BuildDynamicSymbolIndex
= true;
883 std::vector
<std::unique_ptr
<SymbolIndex
>> IdxStack
;
884 #if CLANGD_ENABLE_REMOTE
885 if (RemoteIndexAddress
.empty() != ProjectRoot
.empty()) {
886 llvm::errs() << "remote-index-address and project-path have to be "
887 "specified at the same time.";
890 if (!RemoteIndexAddress
.empty()) {
891 if (IndexFile
.empty()) {
892 log("Connecting to remote index at {0}", RemoteIndexAddress
);
894 elog("When enabling remote index, IndexFile should not be specified. "
895 "Only one can be used at time. Remote index will ignored.");
899 Opts
.BackgroundIndex
= EnableBackgroundIndex
;
900 Opts
.BackgroundIndexPriority
= BackgroundIndexPriority
;
901 Opts
.ReferencesLimit
= ReferencesLimit
;
902 Opts
.Rename
.LimitFiles
= RenameFileLimit
;
903 auto PAI
= createProjectAwareIndex(loadExternalIndex
, Sync
);
904 Opts
.StaticIndex
= PAI
.get();
905 Opts
.AsyncThreadsCount
= WorkerThreadsCount
;
906 Opts
.MemoryCleanup
= getMemoryCleanupFunction();
908 Opts
.CodeComplete
.IncludeIneligibleResults
= IncludeIneligibleResults
;
909 Opts
.CodeComplete
.Limit
= LimitResults
;
910 if (CompletionStyle
.getNumOccurrences())
911 Opts
.CodeComplete
.BundleOverloads
= CompletionStyle
!= Detailed
;
912 Opts
.CodeComplete
.ShowOrigins
= ShowOrigins
;
913 Opts
.CodeComplete
.InsertIncludes
= HeaderInsertion
;
914 Opts
.CodeComplete
.ImportInsertions
= ImportInsertions
;
915 if (!HeaderInsertionDecorators
) {
916 Opts
.CodeComplete
.IncludeIndicator
.Insert
.clear();
917 Opts
.CodeComplete
.IncludeIndicator
.NoInsert
.clear();
919 Opts
.CodeComplete
.EnableFunctionArgSnippets
= EnableFunctionArgSnippets
;
920 Opts
.CodeComplete
.RunParser
= CodeCompletionParse
;
921 Opts
.CodeComplete
.RankingModel
= RankingModel
;
923 RealThreadsafeFS TFS
;
924 std::vector
<std::unique_ptr
<config::Provider
>> ProviderStack
;
925 std::unique_ptr
<config::Provider
> Config
;
927 ProviderStack
.push_back(
928 config::Provider::fromAncestorRelativeYAMLFiles(".clangd", TFS
));
929 llvm::SmallString
<256> UserConfig
;
930 if (llvm::sys::path::user_config_directory(UserConfig
)) {
931 llvm::sys::path::append(UserConfig
, "clangd", "config.yaml");
932 vlog("User config file is {0}", UserConfig
);
933 ProviderStack
.push_back(config::Provider::fromYAMLFile(
934 UserConfig
, /*Directory=*/"", TFS
, /*Trusted=*/true));
936 elog("Couldn't determine user config file, not loading");
939 ProviderStack
.push_back(std::make_unique
<FlagsConfigProvider
>());
940 std::vector
<const config::Provider
*> ProviderPointers
;
941 for (const auto &P
: ProviderStack
)
942 ProviderPointers
.push_back(P
.get());
943 Config
= config::Provider::combine(std::move(ProviderPointers
));
944 Opts
.ConfigProvider
= Config
.get();
946 // Create an empty clang-tidy option.
947 TidyProvider ClangTidyOptProvider
;
948 if (EnableClangTidy
) {
949 std::vector
<TidyProvider
> Providers
;
950 Providers
.reserve(4 + EnableConfig
);
951 Providers
.push_back(provideEnvironment());
952 Providers
.push_back(provideClangTidyFiles(TFS
));
954 Providers
.push_back(provideClangdConfig());
955 Providers
.push_back(provideDefaultChecks());
956 Providers
.push_back(disableUnusableChecks());
957 ClangTidyOptProvider
= combine(std::move(Providers
));
958 Opts
.ClangTidyProvider
= ClangTidyOptProvider
;
960 Opts
.UseDirtyHeaders
= UseDirtyHeaders
;
961 Opts
.PreambleParseForwardingFunctions
= PreambleParseForwardingFunctions
;
962 Opts
.ImportInsertions
= ImportInsertions
;
963 Opts
.QueryDriverGlobs
= std::move(QueryDriverGlobs
);
964 Opts
.TweakFilter
= [&](const Tweak
&T
) {
965 if (T
.hidden() && !HiddenFeatures
)
967 if (TweakList
.getNumOccurrences())
968 return llvm::is_contained(TweakList
, T
.id());
971 if (ForceOffsetEncoding
!= OffsetEncoding::UnsupportedEncoding
)
972 Opts
.Encoding
= ForceOffsetEncoding
;
974 if (CheckFile
.getNumOccurrences()) {
975 llvm::SmallString
<256> Path
;
977 llvm::sys::fs::real_path(CheckFile
, Path
, /*expand_tilde=*/true)) {
978 elog("Failed to resolve path {0}: {1}", CheckFile
, Error
.message());
981 log("Entering check mode (no LSP server)");
982 return check(Path
, TFS
, Opts
)
984 : static_cast<int>(ErrorResultCode::CheckFailed
);
987 // Initialize and run ClangdLSPServer.
988 // Change stdin to binary to not lose \r\n on windows.
989 llvm::sys::ChangeStdinToBinary();
990 std::unique_ptr
<Transport
> TransportLayer
;
991 if (getenv("CLANGD_AS_XPC_SERVICE")) {
993 log("Starting LSP over XPC service");
994 TransportLayer
= newXPCTransport();
996 llvm::errs() << "This clangd binary wasn't built with XPC support.\n";
997 return static_cast<int>(ErrorResultCode::CantRunAsXPCService
);
1000 log("Starting LSP over stdin/stdout");
1001 TransportLayer
= newJSONTransport(
1002 stdin
, llvm::outs(), InputMirrorStream
? &*InputMirrorStream
: nullptr,
1003 PrettyPrint
, InputStyle
);
1005 if (!PathMappingsArg
.empty()) {
1006 auto Mappings
= parsePathMappings(PathMappingsArg
);
1008 elog("Invalid -path-mappings: {0}", Mappings
.takeError());
1011 TransportLayer
= createPathMappingTransport(std::move(TransportLayer
),
1012 std::move(*Mappings
));
1015 ClangdLSPServer
LSPServer(*TransportLayer
, TFS
, Opts
);
1016 llvm::set_thread_name("clangd.main");
1017 int ExitCode
= LSPServer
.run()
1019 : static_cast<int>(ErrorResultCode::NoShutdownRequest
);
1020 log("LSP finished, exiting with status {0}", ExitCode
);
1022 // There may still be lingering background threads (e.g. slow requests
1023 // whose results will be dropped, background index shutting down).
1025 // These should terminate quickly, and ~ClangdLSPServer blocks on them.
1026 // However if a bug causes them to run forever, we want to ensure the process
1027 // eventually exits. As clangd isn't directly user-facing, an editor can
1028 // "leak" clangd processes. Crashing in this case contains the damage.
1029 abortAfterTimeout(std::chrono::minutes(5));
1034 } // namespace clangd
1035 } // namespace clang