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. " 130 opt<bool> EnableClangTidy{
133 desc(
"Enable clang-tidy diagnostics"),
137 opt<std::string> ClangTidyChecks{
140 desc(
"List of clang-tidy checks to run (this will override " 141 ".clang-tidy files). Only meaningful when -clang-tidy flag is on"),
145 opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{
148 desc(
"Whether the clang-parser is used for code-completion"),
150 "Block until the parser can be used"),
152 "Use text-based completion if the parser " 155 "Always used text-based completion")),
162 opt<CompletionStyleFlag> CompletionStyle{
165 desc(
"Granularity of code completion suggestions"),
166 values(clEnumValN(Detailed,
"detailed",
167 "One completion item for each semantically distinct " 168 "completion, with full type information"),
169 clEnumValN(Bundled,
"bundled",
170 "Similar completion items (e.g. function overloads) are " 171 "combined. Type information shown where possible")),
174 opt<std::string> FallbackStyle{
177 desc(
"clang-format style to apply by default when " 178 "no .clang-format file is found"),
179 init(clang::format::DefaultFallbackStyle),
182 opt<bool> EnableFunctionArgSnippets{
183 "function-arg-placeholders",
185 desc(
"When disabled, completions contain only parentheses for " 186 "function calls. When enabled, completions also contain " 187 "placeholders for method parameters"),
192 opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{
195 desc(
"Add #include directives when accepting code completions"),
199 "Include what you use. " 200 "Insert the owning header for top-level symbols, unless the " 201 "header is already directly included or the symbol is " 205 "Never insert #include directives as part of code completion")),
208 opt<bool> HeaderInsertionDecorators{
209 "header-insertion-decorators",
211 desc(
"Prepend a circular dot or space before the completion " 212 "label, depending on whether " 213 "an include line will be inserted or not"),
217 opt<bool> HiddenFeatures{
220 desc(
"Enable hidden features mostly useful to clangd developers"),
225 opt<bool> IncludeIneligibleResults{
226 "include-ineligible-results",
228 desc(
"Include ineligible completion results (e.g. private members)"),
233 opt<bool> EnableIndex{
236 desc(
"Enable index-based features. By default, clangd maintains an index " 237 "built from symbols in opened files. Global index support needs to " 238 "enabled separatedly"),
243 opt<int> LimitResults{
246 desc(
"Limit the number of results returned by clangd. " 247 "0 means no limit (default=100)"),
251 opt<bool> SuggestMissingIncludes{
252 "suggest-missing-includes",
254 desc(
"Attempts to fix diagnostic errors caused by missing " 255 "includes using index"),
259 list<std::string> TweakList{
262 desc(
"Specify a list of Tweaks to enable (only for clangd developers)."),
267 opt<unsigned> WorkerThreadsCount{
270 desc(
"Number of async workers used by clangd. Background index also " 271 "uses this many workers."),
279 "Index file to build the static index. The file must have been created " 280 "by a compatible clangd-indexer\n" 281 "WARNING: This option is experimental only, and will be removed " 282 "eventually. Don't rely on it"),
290 desc(
"Abbreviation for -input-style=delimited -pretty -sync " 291 "-enable-test-scheme -log=verbose. " 292 "Intended to simplify lit tests"),
298 opt<PCHStorageFlag> PCHStorage{
301 desc(
"Storing PCHs in memory increases memory usages, but may " 302 "improve performance"),
304 clEnumValN(PCHStorageFlag::Disk,
"disk",
"store PCHs on disk"),
305 clEnumValN(PCHStorageFlag::Memory,
"memory",
"store PCHs in memory")),
306 init(PCHStorageFlag::Disk),
312 desc(
"Handle client requests on main thread. Background index still uses " 318 opt<JSONStreamStyle> InputStyle{
321 desc(
"Input JSON stream encoding"),
325 "messages delimited by --- lines, with # comment support")),
330 opt<bool> EnableTestScheme{
331 "enable-test-uri-scheme",
333 desc(
"Enable 'test:' URI scheme. Only use in lit tests"),
338 opt<Path> InputMirrorFile{
341 desc(
"Mirror all LSP input to the specified file. Useful for debugging"),
346 opt<Logger::Level> LogLevel{
349 desc(
"Verbosity of log messages written to stderr"),
350 values(clEnumValN(
Logger::Error,
"error",
"Error messages only"),
351 clEnumValN(
Logger::Info,
"info",
"High level execution tracing"),
356 opt<OffsetEncoding> ForceOffsetEncoding{
359 desc(
"Force the offsetEncoding used for character positions. " 360 "This bypasses negotiation via client capabilities"),
364 "Offsets are in UTF-16 code units")),
368 opt<bool> PrettyPrint{
371 desc(
"Pretty-print JSON output"),
381 llvm::Expected<std::string>
382 getAbsolutePath(llvm::StringRef , llvm::StringRef Body,
383 llvm::StringRef )
const override {
387 if (!Body.startswith(
"/"))
388 return llvm::make_error<llvm::StringError>(
389 "Expect URI body to be an absolute path starting with '/': " + Body,
390 llvm::inconvertibleErrorCode());
391 Body = Body.ltrim(
'/');
392 llvm::SmallVector<char, 16>
Path(Body.begin(), Body.end());
395 return std::string(
Path.begin(),
Path.end());
399 uriFromAbsolutePath(llvm::StringRef AbsolutePath)
const override {
400 llvm::StringRef Body = AbsolutePath;
401 if (!Body.consume_front(TestScheme::TestDir)) {
402 return llvm::make_error<llvm::StringError>(
403 "Path " + AbsolutePath +
" doesn't start with root " + TestDir,
404 llvm::inconvertibleErrorCode());
407 return URI(
"test",
"",
408 llvm::sys::path::convert_to_slash(Body));
412 const static char TestDir[];
416 const char TestScheme::TestDir[] =
"C:\\clangd-test";
418 const char TestScheme::TestDir[] =
"/clangd-test";
430 int main(
int argc,
char *argv[]) {
431 using namespace clang;
434 llvm::InitializeAllTargetInfos();
435 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
436 llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) {
437 OS << clang::getClangToolFullVersion(
"clangd") <<
"\n";
439 const char *FlagsEnvVar =
"CLANGD_FLAGS";
440 const char *Overview =
441 R
"(clangd is a language server that provides IDE-like features to editors. 443 It should be used via an editor plugin rather than invoked directly. For more information, see: 444 https://clang.llvm.org/extra/clangd/ 445 https://microsoft.github.io/language-server-protocol/ 447 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. 449 llvm::cl::HideUnrelatedOptions(ClangdCategories); 450 llvm::cl::ParseCommandLineOptions(argc, argv, Overview, 451 nullptr, FlagsEnvVar);
460 if (Test || EnableTestScheme) {
461 static URISchemeRegistry::Add<TestScheme>
X(
462 "test",
"Test scheme for clangd lit tests.");
465 if (!Sync && WorkerThreadsCount == 0) {
466 llvm::errs() <<
"A number of worker threads cannot be 0. Did you mean to " 472 if (WorkerThreadsCount.getNumOccurrences())
473 llvm::errs() <<
"Ignoring -j because -sync is set.\n";
474 WorkerThreadsCount = 0;
476 if (FallbackStyle.getNumOccurrences())
477 clang::format::DefaultFallbackStyle = FallbackStyle.c_str();
480 llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
481 if (!InputMirrorFile.empty()) {
483 InputMirrorStream.emplace(InputMirrorFile, EC,
484 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
486 InputMirrorStream.reset();
487 llvm::errs() <<
"Error while opening an input mirror file: " 490 InputMirrorStream->SetUnbuffered();
497 llvm::Optional<llvm::raw_fd_ostream> TraceStream;
498 std::unique_ptr<trace::EventTracer> Tracer;
499 if (
auto *TraceFile = getenv(
"CLANGD_TRACE")) {
501 TraceStream.emplace(TraceFile, EC,
502 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
505 llvm::errs() <<
"Error while opening trace file " << TraceFile <<
": " 512 llvm::Optional<trace::Session> TracingSession;
514 TracingSession.emplace(*Tracer);
519 if (llvm::outs().is_displayed() && llvm::errs().is_displayed())
520 llvm::errs() << Overview <<
"\n";
523 llvm::errs().SetBuffered();
527 log(
"{0}", clang::getClangToolFullVersion(
"clangd"));
529 SmallString<128> CWD;
530 if (
auto Err = llvm::sys::fs::current_path(CWD))
531 log(
"Working directory unknown: {0}", Err.message());
533 log(
"Working directory: {0}", CWD);
535 for (
int I = 0; I < argc; ++I)
536 log(
"argv[{0}]: {1}", I, argv[I]);
537 if (
auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
538 log(
"{0}: {1}", FlagsEnvVar, *EnvFlags);
542 llvm::Optional<Path> CompileCommandsDirPath;
543 if (!CompileCommandsDir.empty()) {
544 if (llvm::sys::fs::exists(CompileCommandsDir)) {
549 llvm::SmallString<128>
Path(CompileCommandsDir);
551 llvm::errs() <<
"Error while converting the relative path specified by " 552 "--compile-commands-dir to an absolute path: " 553 << EC.message() <<
". The argument will be ignored.\n";
555 CompileCommandsDirPath = Path.str();
559 <<
"Path specified by --compile-commands-dir does not exist. The " 560 "argument will be ignored.\n";
565 switch (PCHStorage) {
566 case PCHStorageFlag::Memory:
569 case PCHStorageFlag::Disk:
573 if (!ResourceDir.empty())
577 std::unique_ptr<SymbolIndex> StaticIdx;
578 std::future<void> AsyncIndexLoad;
579 if (EnableIndex && !IndexFile.empty()) {
582 StaticIdx.
reset(Placeholder =
new SwapIndex(llvm::make_unique<MemIndex>()));
583 AsyncIndexLoad = runAsync<void>([Placeholder] {
584 if (
auto Idx =
loadIndex(IndexFile,
true))
585 Placeholder->
reset(std::move(Idx));
588 AsyncIndexLoad.wait();
595 CCOpts.
Limit = LimitResults;
596 if (CompletionStyle.getNumOccurrences())
600 if (!HeaderInsertionDecorators) {
612 llvm::sys::ChangeStdinToBinary();
614 std::unique_ptr<Transport> TransportLayer;
615 if (getenv(
"CLANGD_AS_XPC_SERVICE")) {
617 log(
"Starting LSP over XPC service");
620 llvm::errs() <<
"This clangd binary wasn't built with XPC support.\n";
624 log(
"Starting LSP over stdin/stdout");
627 InputMirrorStream ? InputMirrorStream.getPointer() :
nullptr,
628 PrettyPrint, InputStyle);
632 std::mutex ClangTidyOptMu;
633 std::unique_ptr<tidy::ClangTidyOptionsProvider>
634 ClangTidyOptProvider;
635 if (EnableClangTidy) {
637 OverrideClangTidyOptions.Checks = ClangTidyChecks;
638 ClangTidyOptProvider = llvm::make_unique<tidy::FileOptionsProvider>(
643 llvm::StringRef
File) {
645 std::lock_guard<std::mutex> Lock(ClangTidyOptMu);
647 return ClangTidyOptProvider->getOptions(
File);
654 if (T.hidden() && !HiddenFeatures)
656 if (TweakList.getNumOccurrences())
657 return llvm::is_contained(TweakList, T.id());
660 llvm::Optional<OffsetEncoding> OffsetEncodingFromFlag;
662 OffsetEncodingFromFlag = ForceOffsetEncoding;
664 *TransportLayer, FSProvider, CCOpts, CompileCommandsDirPath,
665 CompileArgsFrom == FilesystemCompileArgs,
666 OffsetEncodingFromFlag, Opts);
667 llvm::set_thread_name(
"clangd.main");
668 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