11 #include "Features.inc" 18 #include "clang/Basic/Version.h" 19 #include "clang/Format/Format.h" 20 #include "llvm/ADT/Optional.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/Support/CommandLine.h" 23 #include "llvm/Support/FileSystem.h" 24 #include "llvm/Support/Path.h" 25 #include "llvm/Support/Process.h" 26 #include "llvm/Support/Program.h" 27 #include "llvm/Support/Signals.h" 28 #include "llvm/Support/TargetSelect.h" 29 #include "llvm/Support/raw_ostream.h" 42 using llvm::cl::CommaSeparated;
44 using llvm::cl::Hidden;
48 using llvm::cl::OptionCategory;
49 using llvm::cl::values;
53 OptionCategory CompileCommands(
"clangd compilation flags options");
54 OptionCategory Features(
"clangd feature options");
55 OptionCategory Misc(
"clangd miscellaneous options");
56 OptionCategory Protocol(
"clangd protocol and logging options");
57 const OptionCategory *ClangdCategories[] = {&Features, &Protocol,
58 &CompileCommands, &Misc};
64 desc(
"The source of compile commands"),
65 values(clEnumValN(LSPCompileArgs,
"lsp",
66 "All compile commands come from LSP and " 67 "'compile_commands.json' files are ignored"),
68 clEnumValN(FilesystemCompileArgs,
"filesystem",
69 "All compile commands come from the " 70 "'compile_commands.json' files")),
71 init(FilesystemCompileArgs),
75 opt<Path> CompileCommandsDir{
76 "compile-commands-dir",
78 desc(
"Specify a path to look for compile_commands.json. If path " 79 "is invalid, clangd will look in the current directory and " 80 "parent paths of each source file"),
83 opt<Path> ResourceDir{
86 desc(
"Directory for system clang headers"),
91 list<std::string> QueryDriverGlobs{
95 "Comma separated list of globs for white-listing gcc-compatible " 96 "drivers that are safe to execute. Drivers matching any of these globs " 97 "will be used to extract system includes. e.g. " 98 "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"),
104 opt<bool> AllScopesCompletion{
105 "all-scopes-completion",
107 desc(
"If set to true, code completion will include index symbols that are " 108 "not defined in the scopes (e.g. " 109 "namespaces) visible from the code completion point. Such completions " 110 "can insert scope qualifiers"),
114 opt<bool> ShowOrigins{
117 desc(
"Show origins of completion items"),
122 opt<bool> EnableBackgroundIndex{
125 desc(
"Index project code in the background and persist index on disk."),
129 opt<bool> EnableClangTidy{
132 desc(
"Enable clang-tidy diagnostics"),
136 opt<std::string> ClangTidyChecks{
139 desc(
"List of clang-tidy checks to run (this will override " 140 ".clang-tidy files). Only meaningful when -clang-tidy flag is on"),
144 opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{
147 desc(
"Whether the clang-parser is used for code-completion"),
149 "Block until the parser can be used"),
151 "Use text-based completion if the parser " 154 "Always used text-based completion")),
161 opt<CompletionStyleFlag> CompletionStyle{
164 desc(
"Granularity of code completion suggestions"),
165 values(clEnumValN(Detailed,
"detailed",
166 "One completion item for each semantically distinct " 167 "completion, with full type information"),
168 clEnumValN(Bundled,
"bundled",
169 "Similar completion items (e.g. function overloads) are " 170 "combined. Type information shown where possible")),
173 opt<std::string> FallbackStyle{
176 desc(
"clang-format style to apply by default when " 177 "no .clang-format file is found"),
178 init(clang::format::DefaultFallbackStyle),
181 opt<bool> EnableFunctionArgSnippets{
182 "function-arg-placeholders",
184 desc(
"When disabled, completions contain only parentheses for " 185 "function calls. When enabled, completions also contain " 186 "placeholders for method parameters"),
191 opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{
194 desc(
"Add #include directives when accepting code completions"),
198 "Include what you use. " 199 "Insert the owning header for top-level symbols, unless the " 200 "header is already directly included or the symbol is " 204 "Never insert #include directives as part of code completion")),
207 opt<bool> HeaderInsertionDecorators{
208 "header-insertion-decorators",
210 desc(
"Prepend a circular dot or space before the completion " 211 "label, depending on whether " 212 "an include line will be inserted or not"),
216 opt<bool> HiddenFeatures{
219 desc(
"Enable hidden features mostly useful to clangd developers"),
224 opt<bool> IncludeIneligibleResults{
225 "include-ineligible-results",
227 desc(
"Include ineligible completion results (e.g. private members)"),
232 opt<bool> EnableIndex{
235 desc(
"Enable index-based features. By default, clangd maintains an index " 236 "built from symbols in opened files. Global index support needs to " 237 "enabled separatedly"),
242 opt<int> LimitResults{
245 desc(
"Limit the number of results returned by clangd. " 246 "0 means no limit (default=100)"),
250 opt<bool> SuggestMissingIncludes{
251 "suggest-missing-includes",
253 desc(
"Attempts to fix diagnostic errors caused by missing " 254 "includes using index"),
258 list<std::string> TweakList{
261 desc(
"Specify a list of Tweaks to enable (only for clangd developers)."),
266 opt<unsigned> WorkerThreadsCount{
269 desc(
"Number of async workers used by clangd. Background index also " 270 "uses this many workers."),
278 "Index file to build the static index. The file must have been created " 279 "by a compatible clangd-indexer\n" 280 "WARNING: This option is experimental only, and will be removed " 281 "eventually. Don't rely on it"),
289 desc(
"Abbreviation for -input-style=delimited -pretty -sync " 290 "-enable-test-scheme -log=verbose. " 291 "Intended to simplify lit tests"),
297 opt<PCHStorageFlag> PCHStorage{
300 desc(
"Storing PCHs in memory increases memory usages, but may " 301 "improve performance"),
303 clEnumValN(PCHStorageFlag::Disk,
"disk",
"store PCHs on disk"),
304 clEnumValN(PCHStorageFlag::Memory,
"memory",
"store PCHs in memory")),
305 init(PCHStorageFlag::Disk),
311 desc(
"Handle client requests on main thread. Background index still uses " 317 opt<JSONStreamStyle> InputStyle{
320 desc(
"Input JSON stream encoding"),
324 "messages delimited by --- lines, with # comment support")),
329 opt<bool> EnableTestScheme{
330 "enable-test-uri-scheme",
332 desc(
"Enable 'test:' URI scheme. Only use in lit tests"),
337 opt<Path> InputMirrorFile{
340 desc(
"Mirror all LSP input to the specified file. Useful for debugging"),
345 opt<Logger::Level> LogLevel{
348 desc(
"Verbosity of log messages written to stderr"),
349 values(clEnumValN(
Logger::Error,
"error",
"Error messages only"),
350 clEnumValN(
Logger::Info,
"info",
"High level execution tracing"),
355 opt<OffsetEncoding> ForceOffsetEncoding{
358 desc(
"Force the offsetEncoding used for character positions. " 359 "This bypasses negotiation via client capabilities"),
363 "Offsets are in UTF-16 code units")),
367 opt<bool> PrettyPrint{
370 desc(
"Pretty-print JSON output"),
380 llvm::Expected<std::string>
381 getAbsolutePath(llvm::StringRef , llvm::StringRef Body,
382 llvm::StringRef )
const override {
386 if (!Body.startswith(
"/"))
387 return llvm::make_error<llvm::StringError>(
388 "Expect URI body to be an absolute path starting with '/': " + Body,
389 llvm::inconvertibleErrorCode());
390 Body = Body.ltrim(
'/');
391 llvm::SmallVector<char, 16>
Path(Body.begin(), Body.end());
394 return std::string(
Path.begin(),
Path.end());
398 uriFromAbsolutePath(llvm::StringRef AbsolutePath)
const override {
399 llvm::StringRef Body = AbsolutePath;
400 if (!Body.consume_front(TestScheme::TestDir)) {
401 return llvm::make_error<llvm::StringError>(
402 "Path " + AbsolutePath +
" doesn't start with root " + TestDir,
403 llvm::inconvertibleErrorCode());
406 return URI(
"test",
"",
407 llvm::sys::path::convert_to_slash(Body));
411 const static char TestDir[];
415 const char TestScheme::TestDir[] =
"C:\\clangd-test";
417 const char TestScheme::TestDir[] =
"/clangd-test";
429 int main(
int argc,
char *argv[]) {
430 using namespace clang;
433 llvm::InitializeAllTargetInfos();
434 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
435 llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) {
436 OS << clang::getClangToolFullVersion(
"clangd") <<
"\n";
438 const char *FlagsEnvVar =
"CLANGD_FLAGS";
439 const char *Overview =
440 R
"(clangd is a language server that provides IDE-like features to editors. 442 It should be used via an editor plugin rather than invoked directly. For more information, see: 443 https://clang.llvm.org/extra/clangd/ 444 https://microsoft.github.io/language-server-protocol/ 446 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. 448 llvm::cl::HideUnrelatedOptions(ClangdCategories); 449 llvm::cl::ParseCommandLineOptions(argc, argv, Overview, 450 nullptr, FlagsEnvVar);
459 if (Test || EnableTestScheme) {
460 static URISchemeRegistry::Add<TestScheme>
X(
461 "test",
"Test scheme for clangd lit tests.");
464 if (!Sync && WorkerThreadsCount == 0) {
465 llvm::errs() <<
"A number of worker threads cannot be 0. Did you mean to " 471 if (WorkerThreadsCount.getNumOccurrences())
472 llvm::errs() <<
"Ignoring -j because -sync is set.\n";
473 WorkerThreadsCount = 0;
475 if (FallbackStyle.getNumOccurrences())
476 clang::format::DefaultFallbackStyle = FallbackStyle.c_str();
479 llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
480 if (!InputMirrorFile.empty()) {
482 InputMirrorStream.emplace(InputMirrorFile, EC,
483 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
485 InputMirrorStream.reset();
486 llvm::errs() <<
"Error while opening an input mirror file: " 489 InputMirrorStream->SetUnbuffered();
496 llvm::Optional<llvm::raw_fd_ostream> TraceStream;
497 std::unique_ptr<trace::EventTracer> Tracer;
498 if (
auto *TraceFile = getenv(
"CLANGD_TRACE")) {
500 TraceStream.emplace(TraceFile, EC,
501 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
504 llvm::errs() <<
"Error while opening trace file " << TraceFile <<
": " 511 llvm::Optional<trace::Session> TracingSession;
513 TracingSession.emplace(*Tracer);
518 if (llvm::outs().is_displayed() && llvm::errs().is_displayed())
519 llvm::errs() << Overview <<
"\n";
522 llvm::errs().SetBuffered();
526 log(
"{0}", clang::getClangToolFullVersion(
"clangd"));
528 SmallString<128> CWD;
529 if (
auto Err = llvm::sys::fs::current_path(CWD))
530 log(
"Working directory unknown: {0}", Err.message());
532 log(
"Working directory: {0}", CWD);
534 for (
int I = 0; I < argc; ++I)
535 log(
"argv[{0}]: {1}", I, argv[I]);
536 if (
auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
537 log(
"{0}: {1}", FlagsEnvVar, *EnvFlags);
541 llvm::Optional<Path> CompileCommandsDirPath;
542 if (!CompileCommandsDir.empty()) {
543 if (llvm::sys::fs::exists(CompileCommandsDir)) {
548 llvm::SmallString<128>
Path(CompileCommandsDir);
550 llvm::errs() <<
"Error while converting the relative path specified by " 551 "--compile-commands-dir to an absolute path: " 552 << EC.message() <<
". The argument will be ignored.\n";
554 CompileCommandsDirPath = Path.str();
558 <<
"Path specified by --compile-commands-dir does not exist. The " 559 "argument will be ignored.\n";
564 switch (PCHStorage) {
565 case PCHStorageFlag::Memory:
568 case PCHStorageFlag::Disk:
572 if (!ResourceDir.empty())
576 std::unique_ptr<SymbolIndex> StaticIdx;
577 std::future<void> AsyncIndexLoad;
578 if (EnableIndex && !IndexFile.empty()) {
581 StaticIdx.
reset(Placeholder =
new SwapIndex(llvm::make_unique<MemIndex>()));
582 AsyncIndexLoad = runAsync<void>([Placeholder] {
583 if (
auto Idx =
loadIndex(IndexFile,
true))
584 Placeholder->
reset(std::move(Idx));
587 AsyncIndexLoad.wait();
594 CCOpts.
Limit = LimitResults;
595 if (CompletionStyle.getNumOccurrences())
599 if (!HeaderInsertionDecorators) {
611 llvm::sys::ChangeStdinToBinary();
613 std::unique_ptr<Transport> TransportLayer;
614 if (getenv(
"CLANGD_AS_XPC_SERVICE")) {
616 log(
"Starting LSP over XPC service");
619 llvm::errs() <<
"This clangd binary wasn't built with XPC support.\n";
623 log(
"Starting LSP over stdin/stdout");
626 InputMirrorStream ? InputMirrorStream.getPointer() :
nullptr,
627 PrettyPrint, InputStyle);
631 std::mutex ClangTidyOptMu;
632 std::unique_ptr<tidy::ClangTidyOptionsProvider>
633 ClangTidyOptProvider;
634 if (EnableClangTidy) {
636 OverrideClangTidyOptions.Checks = ClangTidyChecks;
637 ClangTidyOptProvider = llvm::make_unique<tidy::FileOptionsProvider>(
642 llvm::StringRef
File) {
644 std::lock_guard<std::mutex> Lock(ClangTidyOptMu);
646 return ClangTidyOptProvider->getOptions(
File);
653 if (T.hidden() && !HiddenFeatures)
655 if (TweakList.getNumOccurrences())
656 return llvm::is_contained(TweakList, T.id());
659 llvm::Optional<OffsetEncoding> OffsetEncodingFromFlag;
661 OffsetEncodingFromFlag = ForceOffsetEncoding;
663 *TransportLayer, FSProvider, CCOpts, CompileCommandsDirPath,
664 CompileArgsFrom == FilesystemCompileArgs,
665 OffsetEncodingFromFlag, Opts);
666 llvm::set_thread_name(
"clangd.main");
667 return LSPServer.
run() ? 0
bool ShowOrigins
Expose origins of completion items in the label (for debugging).
std::function< bool(const Tweak &)> TweakFilter
Returns true if the tweak should be enabled.
size_t Limit
Limit the number of results returned (0 means no limit).
Always use text-based completion.
int main(int argc, char *argv[])
std::unique_ptr< SymbolIndex > loadIndex(llvm::StringRef SymbolFilename, bool UseDex)
bool BackgroundIndex
If true, ClangdServer automatically indexes files in the current project on background threads...
URIScheme is an extension point for teaching clangd to recognize a custom URI scheme.
std::unique_ptr< Transport > newXPCTransport()
bool run()
Run LSP server loop, communicating with the Transport provided in the constructor.
Run the parser if inputs (preamble) are ready.
def make_absolute(f, directory)
unsigned AsyncThreadsCount
To process requests asynchronously, ClangdServer spawns worker threads.
bool BuildDynamicSymbolIndex
If true, ClangdServer builds a dynamic in-memory index for symbols in opened files and uses the index...
MockFSProvider FSProvider
static void preventThreadStarvationInTests()
Interface to allow custom logging in clangd.
bool SpeculativeIndexRequest
If set to true, this will send an asynchronous speculative index request, based on the index request ...
bool SuggestMissingIncludes
void log(const char *Fmt, Ts &&... Vals)
std::string Path
A typedef to represent a file path.
Only one LoggingSession can be active at a time.
bool IncludeIneligibleResults
Include results that are not legal completions in the current context.
enum clang::clangd::CodeCompleteOptions::CodeCompletionParse RunParser
std::unique_ptr< Transport > newJSONTransport(std::FILE *In, llvm::raw_ostream &Out, llvm::raw_ostream *InMirror, bool Pretty, JSONStreamStyle Style)
llvm::Optional< bool > BundleOverloads
Combine overloads into a single completion item where possible.
unsigned getDefaultAsyncThreadsCount()
Returns a number of a default async threads to use for TUScheduler.
Block until we can run the parser (e.g.
bool StorePreamblesInMemory
Cached preambles are potentially large. If false, store them on disk.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static URISchemeRegistry::Add< TestScheme > X(TestScheme::Scheme, "Test schema")
llvm::Optional< std::string > ResourceDir
The resource directory is used to find internal headers, overriding defaults and -resource-dir compil...
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...
struct clang::clangd::CodeCompleteOptions::IncludeInsertionIndicator IncludeIndicator
std::vector< std::string > QueryDriverGlobs
Clangd will execute compiler drivers matching one of these globs to fetch system include path...
A URI describes the location of a source file.
An interface base for small context-sensitive refactoring actions.
bool EnableFunctionArgSnippets
Whether to generate snippets for function arguments on code-completion.
ClangTidyOptionsBuilder GetClangTidyOptions
If set, enable clang-tidy in clangd and use to it get clang-tidy configurations for a particular file...
bool AllScopes
Whether to include index symbols that are not defined in the scopes visible from the code completion ...
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getFileSystem() const override
Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.
This class exposes ClangdServer's capabilities via Language Server Protocol.
SymbolIndex * StaticIndex
If set, use this index to augment code completion results.
void reset(std::unique_ptr< SymbolIndex >)
enum clang::clangd::CodeCompleteOptions::IncludeInsertion InsertIncludes