31 #include "clang/Format/Format.h"
32 #include "llvm/ADT/Optional.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringRef.h"
35 #include "llvm/Support/CommandLine.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/Path.h"
38 #include "llvm/Support/Process.h"
39 #include "llvm/Support/Program.h"
40 #include "llvm/Support/Signals.h"
41 #include "llvm/Support/TargetSelect.h"
42 #include "llvm/Support/raw_ostream.h"
64 bool check(
const llvm::StringRef File, llvm::Optional<Range> LineRange,
65 const ThreadsafeFS &TFS,
const ClangdLSPServer::Options &Opts,
66 bool EnableCodeCompletion);
71 using llvm::cl::CommaSeparated;
73 using llvm::cl::Hidden;
77 using llvm::cl::OptionCategory;
78 using llvm::cl::ValueOptional;
79 using llvm::cl::values;
83 OptionCategory CompileCommands(
"clangd compilation flags options");
84 OptionCategory Features(
"clangd feature options");
85 OptionCategory Misc(
"clangd miscellaneous options");
86 OptionCategory Protocol(
"clangd protocol and logging options");
87 OptionCategory Retired(
"clangd flags no longer in use");
88 const OptionCategory *ClangdCategories[] = {&Features, &Protocol,
89 &CompileCommands, &Misc, &Retired};
91 template <
typename T>
class RetiredFlag {
95 RetiredFlag(llvm::StringRef
Name)
96 : Option(
Name, cat(Retired), desc(
"Obsolete flag, ignored"), Hidden,
97 llvm::cl::callback([
Name](const T &) {
99 <<
"The flag `-" <<
Name <<
"` is obsolete and ignored.\n";
103 enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs };
104 opt<CompileArgsFrom> CompileArgsFrom{
106 cat(CompileCommands),
107 desc(
"The source of compile commands"),
108 values(clEnumValN(LSPCompileArgs,
"lsp",
109 "All compile commands come from LSP and "
110 "'compile_commands.json' files are ignored"),
111 clEnumValN(FilesystemCompileArgs,
"filesystem",
112 "All compile commands come from the "
113 "'compile_commands.json' files")),
114 init(FilesystemCompileArgs),
118 opt<Path> CompileCommandsDir{
119 "compile-commands-dir",
120 cat(CompileCommands),
121 desc(
"Specify a path to look for compile_commands.json. If path "
122 "is invalid, clangd will look in the current directory and "
123 "parent paths of each source file"),
126 opt<Path> ResourceDir{
128 cat(CompileCommands),
129 desc(
"Directory for system clang headers"),
134 list<std::string> QueryDriverGlobs{
136 cat(CompileCommands),
138 "Comma separated list of globs for white-listing gcc-compatible "
139 "drivers that are safe to execute. Drivers matching any of these globs "
140 "will be used to extract system includes. e.g. "
141 "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"),
147 opt<bool> AllScopesCompletion{
148 "all-scopes-completion",
150 desc(
"If set to true, code completion will include index symbols that are "
151 "not defined in the scopes (e.g. "
152 "namespaces) visible from the code completion point. Such completions "
153 "can insert scope qualifiers"),
157 opt<bool> ShowOrigins{
160 desc(
"Show origins of completion items"),
161 init(CodeCompleteOptions().ShowOrigins),
165 opt<bool> EnableBackgroundIndex{
168 desc(
"Index project code in the background and persist index on disk."),
172 opt<llvm::ThreadPriority> BackgroundIndexPriority{
173 "background-index-priority",
175 desc(
"Thread priority for building the background index. "
176 "The effect of this flag is OS-specific."),
177 values(clEnumValN(llvm::ThreadPriority::Background,
"background",
178 "Minimum priority, runs on idle CPUs. "
179 "May leave 'performance' cores unused."),
180 clEnumValN(llvm::ThreadPriority::Low,
"low",
181 "Reduced priority compared to interactive work."),
182 clEnumValN(llvm::ThreadPriority::Default,
"normal",
183 "Same priority as other clangd work.")),
184 init(llvm::ThreadPriority::Low),
187 opt<bool> EnableClangTidy{
190 desc(
"Enable clang-tidy diagnostics"),
194 opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{
197 desc(
"Whether the clang-parser is used for code-completion"),
199 "Block until the parser can be used"),
201 "Use text-based completion if the parser "
204 "Always used text-based completion")),
205 init(CodeCompleteOptions().RunParser),
209 opt<CodeCompleteOptions::CodeCompletionRankingModel> RankingModel{
212 desc(
"Model to use to rank code-completion items"),
214 "Use hueristics to rank code completion items"),
216 "Use Decision Forest model to rank completion items")),
217 init(CodeCompleteOptions().RankingModel),
222 enum CompletionStyleFlag { Detailed, Bundled };
223 opt<CompletionStyleFlag> CompletionStyle{
226 desc(
"Granularity of code completion suggestions"),
227 values(clEnumValN(Detailed,
"detailed",
228 "One completion item for each semantically distinct "
229 "completion, with full type information"),
230 clEnumValN(Bundled,
"bundled",
231 "Similar completion items (e.g. function overloads) are "
232 "combined. Type information shown where possible")),
235 opt<std::string> FallbackStyle{
238 desc(
"clang-format style to apply by default when "
239 "no .clang-format file is found"),
240 init(clang::format::DefaultFallbackStyle),
243 opt<bool> EnableFunctionArgSnippets{
244 "function-arg-placeholders",
246 desc(
"When disabled, completions contain only parentheses for "
247 "function calls. When enabled, completions also contain "
248 "placeholders for method parameters"),
249 init(CodeCompleteOptions().EnableFunctionArgSnippets),
252 opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{
255 desc(
"Add #include directives when accepting code completions"),
256 init(CodeCompleteOptions().InsertIncludes),
259 "Include what you use. "
260 "Insert the owning header for top-level symbols, unless the "
261 "header is already directly included or the symbol is "
265 "Never insert #include directives as part of code completion")),
268 opt<bool> IncludeCleanerStdlib{
269 "include-cleaner-stdlib",
271 desc(
"Apply include-cleaner analysis to standard library headers "
277 opt<bool> HeaderInsertionDecorators{
278 "header-insertion-decorators",
280 desc(
"Prepend a circular dot or space before the completion "
281 "label, depending on whether "
282 "an include line will be inserted or not"),
286 opt<bool> HiddenFeatures{
289 desc(
"Enable hidden features mostly useful to clangd developers"),
294 opt<bool> IncludeIneligibleResults{
295 "include-ineligible-results",
297 desc(
"Include ineligible completion results (e.g. private members)"),
298 init(CodeCompleteOptions().IncludeIneligibleResults),
302 RetiredFlag<bool> EnableIndex(
"index");
303 RetiredFlag<bool> SuggestMissingIncludes(
"suggest-missing-includes");
304 RetiredFlag<bool> RecoveryAST(
"recovery-ast");
305 RetiredFlag<bool> RecoveryASTType(
"recovery-ast-type");
306 RetiredFlag<bool> AsyncPreamble(
"async-preamble");
307 RetiredFlag<bool> CollectMainFileRefs(
"collect-main-file-refs");
308 RetiredFlag<bool> CrossFileRename(
"cross-file-rename");
309 RetiredFlag<std::string> ClangTidyChecks(
"clang-tidy-checks");
310 RetiredFlag<std::string> InlayHints(
"inlay-hints");
312 opt<int> LimitResults{
315 desc(
"Limit the number of results returned by clangd. "
316 "0 means no limit (default=100)"),
320 opt<int> ReferencesLimit{
323 desc(
"Limit the number of references returned by clangd. "
324 "0 means no limit (default=1000)"),
328 list<std::string> TweakList{
331 desc(
"Specify a list of Tweaks to enable (only for clangd developers)."),
336 opt<bool> FoldingRanges{
339 desc(
"Enable preview of FoldingRanges feature"),
344 opt<unsigned> WorkerThreadsCount{
347 desc(
"Number of async workers used by clangd. Background index also "
348 "uses this many workers."),
356 "Index file to build the static index. The file must have been created "
357 "by a compatible clangd-indexer\n"
358 "WARNING: This option is experimental only, and will be removed "
359 "eventually. Don't rely on it"),
367 desc(
"Abbreviation for -input-style=delimited -pretty -sync "
368 "-enable-test-scheme -enable-config=0 -log=verbose -crash-pragmas. "
369 "Intended to simplify lit tests"),
374 opt<bool> CrashPragmas{
377 desc(
"Respect `#pragma clang __debug crash` and friends."),
385 desc(
"Parse one file in isolation instead of acting as a language server. "
386 "Useful to investigate/reproduce crashes or configuration problems. "
387 "With --check=<filename>, attempts to parse a particular file."),
392 opt<std::string> CheckFileLines{
395 desc(
"If specified, limits the range of tokens in -check file on which "
396 "various features are tested. Example --check-lines=3-7 restricts "
397 "testing to lines 3 to 7 (inclusive) or --check-lines=5 to restrict "
398 "to one line. Default is testing entire file."),
403 enum PCHStorageFlag { Disk, Memory };
404 opt<PCHStorageFlag> PCHStorage{
407 desc(
"Storing PCHs in memory increases memory usages, but may "
408 "improve performance"),
410 clEnumValN(PCHStorageFlag::Disk,
"disk",
"store PCHs on disk"),
411 clEnumValN(PCHStorageFlag::Memory,
"memory",
"store PCHs in memory")),
412 init(PCHStorageFlag::Disk),
418 desc(
"Handle client requests on main thread. Background index still uses "
424 opt<JSONStreamStyle> InputStyle{
427 desc(
"Input JSON stream encoding"),
431 "messages delimited by --- lines, with # comment support")),
436 opt<bool> EnableTestScheme{
437 "enable-test-uri-scheme",
439 desc(
"Enable 'test:' URI scheme. Only use in lit tests"),
444 opt<std::string> PathMappingsArg{
448 "Translates between client paths (as seen by a remote editor) and "
449 "server paths (where clangd sees files on disk). "
450 "Comma separated list of '<client_path>=<server_path>' pairs, the "
451 "first entry matching a given path is used. "
452 "e.g. /home/project/incl=/opt/include,/home/project=/workarea/project"),
456 opt<Path> InputMirrorFile{
459 desc(
"Mirror all LSP input to the specified file. Useful for debugging"),
464 opt<Logger::Level> LogLevel{
467 desc(
"Verbosity of log messages written to stderr"),
468 values(clEnumValN(
Logger::Error,
"error",
"Error messages only"),
469 clEnumValN(
Logger::Info,
"info",
"High level execution tracing"),
474 opt<OffsetEncoding> ForceOffsetEncoding{
477 desc(
"Force the offsetEncoding used for character positions. "
478 "This bypasses negotiation via client capabilities"),
482 "Offsets are in UTF-16 code units"),
484 "Offsets are in unicode codepoints")),
488 opt<bool> PrettyPrint{
491 desc(
"Pretty-print JSON output"),
495 opt<bool> EnableConfig{
499 "Read user and project configuration from YAML files.\n"
500 "Project config is from a .clangd file in the project directory.\n"
501 "User config is from clangd/config.yaml in the following directories:\n"
502 "\tWindows: %USERPROFILE%\\AppData\\Local\n"
503 "\tMac OS: ~/Library/Preferences/\n"
504 "\tOthers: $XDG_CONFIG_HOME, usually ~/.config\n"
505 "Configuration is documented at https://clangd.llvm.org/config.html"),
509 opt<bool> UseDirtyHeaders{
"use-dirty-headers", cat(Misc),
510 desc(
"Use files open in the editor when parsing "
511 "headers instead of reading from the disk"),
513 init(ClangdServer::Options().UseDirtyHeaders)};
515 opt<bool> PreambleParseForwardingFunctions{
516 "parse-forwarding-functions",
518 desc(
"Parse all emplace-like functions in included headers"),
520 init(ParseOptions().PreambleParseForwardingFunctions),
523 #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
524 opt<bool> EnableMallocTrim{
527 desc(
"Release memory periodically via malloc_trim(3)."),
531 std::function<void()> getMemoryCleanupFunction() {
532 if (!EnableMallocTrim)
536 constexpr
size_t MallocTrimPad = 20
'000'000;
538 if (malloc_trim(MallocTrimPad))
539 vlog(
"Released memory via malloc_trim");
543 std::function<void()> getMemoryCleanupFunction() {
return nullptr; }
546 #if CLANGD_ENABLE_REMOTE
547 opt<std::string> RemoteIndexAddress{
548 "remote-index-address",
550 desc(
"Address of the remote index server"),
554 opt<std::string> ProjectRoot{
557 desc(
"Path to the project root. Requires remote-index-address to be set."),
565 class TestScheme :
public URIScheme {
567 llvm::Expected<std::string>
569 llvm::StringRef )
const override {
573 if (!Body.startswith(
"/"))
575 "Expect URI body to be an absolute path starting with '/': {0}",
577 Body = Body.ltrim(
'/');
578 llvm::SmallString<16>
Path(Body);
581 return std::string(
Path);
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",
"",
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",
610 switch (External.Kind) {
614 RemoteIndexUsed.record(1, External.Location);
615 log(
"Associating {0} with remote index at {1}.", External.MountPoint,
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()] {
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 {
642 std::vector<config::CompiledFragment>
643 getFragments(
const config::Params &,
649 FlagsConfigProvider() {
650 llvm::Optional<Config::CDBSearchSpec> CDBSearch;
651 llvm::Optional<Config::ExternalIndexSpec> IndexSpec;
652 llvm::Optional<Config::BackgroundPolicy> BGPolicy;
656 if (!CompileCommandsDir.empty()) {
657 if (llvm::sys::fs::exists(CompileCommandsDir)) {
662 llvm::SmallString<128>
Path(CompileCommandsDir);
664 elog(
"Error while converting the relative path specified by "
665 "--compile-commands-dir to an absolute path: {0}. The argument "
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);
693 if (!EnableBackgroundIndex) {
699 C.CompileFlags.CDBSearch = *CDBSearch;
701 C.Index.External = *IndexSpec;
703 C.Index.Background = *BGPolicy;
704 if (AllScopesCompletion.getNumOccurrences())
705 C.Completion.AllScopes = AllScopesCompletion;
720 int main(
int argc,
char *argv[]) {
721 using namespace clang;
724 llvm::InitializeAllTargetInfos();
725 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
726 llvm::sys::AddSignalHandler(
730 llvm::errs().flush();
734 llvm::cl::SetVersionPrinter([](llvm::raw_ostream &
OS) {
739 const char *FlagsEnvVar =
"CLANGD_FLAGS";
740 const char *Overview =
741 R
"(clangd is a language server that provides IDE-like features to editors.
743 It should be used via an editor plugin rather than invoked directly. For more information, see:
744 https://clangd.llvm.org/
745 https://microsoft.github.io/language-server-protocol/
747 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
749 llvm::cl::HideUnrelatedOptions(ClangdCategories);
750 llvm::cl::ParseCommandLineOptions(argc, argv, Overview,
751 nullptr, FlagsEnvVar);
753 if (!Sync.getNumOccurrences())
755 if (!CrashPragmas.getNumOccurrences())
761 if (!EnableConfig.getNumOccurrences())
762 EnableConfig =
false;
764 if (!EnableBackgroundIndex.getNumOccurrences())
765 EnableBackgroundIndex =
false;
767 else if (EnableBackgroundIndex)
770 if (Test || EnableTestScheme) {
771 static URISchemeRegistry::Add<TestScheme>
X(
772 "test",
"Test scheme for clangd lit tests.");
777 if (!Sync && WorkerThreadsCount == 0) {
778 llvm::errs() <<
"A number of worker threads cannot be 0. Did you mean to "
784 if (WorkerThreadsCount.getNumOccurrences())
785 llvm::errs() <<
"Ignoring -j because -sync is set.\n";
786 WorkerThreadsCount = 0;
788 if (FallbackStyle.getNumOccurrences())
789 clang::format::DefaultFallbackStyle = FallbackStyle.c_str();
792 llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
793 if (!InputMirrorFile.empty()) {
795 InputMirrorStream.emplace(InputMirrorFile, EC,
796 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
798 InputMirrorStream.reset();
799 llvm::errs() <<
"Error while opening an input mirror file: "
802 InputMirrorStream->SetUnbuffered();
809 llvm::Optional<llvm::raw_fd_ostream> TracerStream;
810 std::unique_ptr<trace::EventTracer>
Tracer;
811 const char *JSONTraceFile = getenv(
"CLANGD_TRACE");
812 const char *MetricsCSVFile = getenv(
"CLANGD_METRICS");
813 const char *TracerFile = JSONTraceFile ? JSONTraceFile : MetricsCSVFile;
816 TracerStream.emplace(TracerFile, EC,
817 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
819 TracerStream.reset();
820 llvm::errs() <<
"Error while opening trace file " << TracerFile <<
": "
823 Tracer = (TracerFile == JSONTraceFile)
829 llvm::Optional<trace::Session> TracingSession;
831 TracingSession.emplace(*
Tracer);
836 if (llvm::outs().is_displayed() && llvm::errs().is_displayed() &&
837 !CheckFile.getNumOccurrences())
838 llvm::errs() << Overview <<
"\n";
841 llvm::errs().SetBuffered();
843 llvm::errs().tie(
nullptr);
849 log(
"PID: {0}", llvm::sys::Process::getProcessId());
851 SmallString<128> CWD;
852 if (
auto Err = llvm::sys::fs::current_path(CWD))
853 log(
"Working directory unknown: {0}", Err.message());
855 log(
"Working directory: {0}", CWD);
857 for (
int I = 0; I < argc; ++I)
858 log(
"argv[{0}]: {1}", I, argv[I]);
859 if (
auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
860 log(
"{0}: {1}", FlagsEnvVar, *EnvFlags);
863 Opts.UseDirBasedCDB = (CompileArgsFrom == FilesystemCompileArgs);
865 switch (PCHStorage) {
866 case PCHStorageFlag::Memory:
867 Opts.StorePreamblesInMemory =
true;
869 case PCHStorageFlag::Disk:
870 Opts.StorePreamblesInMemory =
false;
873 if (!ResourceDir.empty())
874 Opts.ResourceDir = ResourceDir;
875 Opts.BuildDynamicSymbolIndex =
true;
876 std::vector<std::unique_ptr<SymbolIndex>> IdxStack;
877 std::unique_ptr<SymbolIndex> StaticIdx;
878 #
if CLANGD_ENABLE_REMOTE
879 if (RemoteIndexAddress.empty() != ProjectRoot.empty()) {
880 llvm::errs() <<
"remote-index-address and project-path have to be "
881 "specified at the same time.";
884 if (!RemoteIndexAddress.empty()) {
885 if (IndexFile.empty()) {
886 log(
"Connecting to remote index at {0}", RemoteIndexAddress);
888 elog(
"When enabling remote index, IndexFile should not be specified. "
889 "Only one can be used at time. Remote index will ignored.");
893 Opts.BackgroundIndex = EnableBackgroundIndex;
894 Opts.BackgroundIndexPriority = BackgroundIndexPriority;
895 Opts.ReferencesLimit = ReferencesLimit;
898 IdxStack.emplace_back(std::move(StaticIdx));
899 IdxStack.emplace_back(
900 std::make_unique<MergedIndex>(PAI.get(), IdxStack.back().get()));
901 Opts.StaticIndex = IdxStack.back().get();
903 Opts.StaticIndex = PAI.get();
905 Opts.AsyncThreadsCount = WorkerThreadsCount;
906 Opts.FoldingRanges = FoldingRanges;
907 Opts.MemoryCleanup = getMemoryCleanupFunction();
910 Opts.CodeComplete.
Limit = LimitResults;
911 if (CompletionStyle.getNumOccurrences())
915 if (!HeaderInsertionDecorators) {
920 Opts.CodeComplete.
RunParser = CodeCompletionParse;
924 std::vector<std::unique_ptr<config::Provider>> ProviderStack;
925 std::unique_ptr<config::Provider>
Config;
927 ProviderStack.push_back(
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);
934 UserConfig,
"", TFS,
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());
944 Opts.ConfigProvider =
Config.get();
948 if (EnableClangTidy) {
949 std::vector<TidyProvider> Providers;
950 Providers.reserve(4 + EnableConfig);
957 ClangTidyOptProvider =
combine(std::move(Providers));
958 Opts.ClangTidyProvider = ClangTidyOptProvider;
960 Opts.UseDirtyHeaders = UseDirtyHeaders;
961 Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
962 Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
963 Opts.TweakFilter = [&](
const Tweak &T) {
964 if (T.hidden() && !HiddenFeatures)
966 if (TweakList.getNumOccurrences())
967 return llvm::is_contained(TweakList, T.id());
971 Opts.Encoding = ForceOffsetEncoding;
974 if (CheckFile.getNumOccurrences()) {
975 llvm::SmallString<256>
Path;
977 llvm::sys::fs::real_path(CheckFile,
Path,
true)) {
978 elog(
"Failed to resolve path {0}: {1}", CheckFile,
Error.message());
981 log(
"Entering check mode (no LSP server)");
982 llvm::Optional<Range> CheckLineRange;
983 if (!CheckFileLines.empty()) {
984 uint32_t Begin = 0, End = std::numeric_limits<uint32_t>::max();
985 StringRef RangeStr(CheckFileLines);
986 bool ParseError = RangeStr.consumeInteger(0, Begin);
987 if (RangeStr.empty()) {
991 ParseError |= RangeStr.consumeInteger(0, End);
993 if (
ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) {
995 "Invalid --check-lines specified. Use Begin-End format, e.g. 3-17");
998 CheckLineRange =
Range{
Position{
static_cast<int>(Begin - 1), 0},
999 Position{
static_cast<int>(End), 0}};
1004 return check(
Path, CheckLineRange, TFS, Opts,
1005 !CheckFileLines.empty())
1009 if (!CheckFileLines.empty()) {
1010 elog(
"--check-lines requires --check");
1016 llvm::sys::ChangeStdinToBinary();
1017 std::unique_ptr<Transport> TransportLayer;
1018 if (getenv(
"CLANGD_AS_XPC_SERVICE")) {
1019 #if CLANGD_BUILD_XPC
1020 log(
"Starting LSP over XPC service");
1023 llvm::errs() <<
"This clangd binary wasn't built with XPC support.\n";
1027 log(
"Starting LSP over stdin/stdout");
1029 stdin, llvm::outs(),
1030 InputMirrorStream ? InputMirrorStream.getPointer() :
nullptr,
1031 PrettyPrint, InputStyle);
1033 if (!PathMappingsArg.empty()) {
1036 elog(
"Invalid -path-mappings: {0}", Mappings.takeError());
1040 std::move(*Mappings));
1044 llvm::set_thread_name(
"clangd.main");
1045 int ExitCode = LSPServer.
run()
1048 log(
"LSP finished, exiting with status {0}", ExitCode);