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"),
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(
"Parse on main thread. If set, -j is ignored"),
316 opt<JSONStreamStyle> InputStyle{
319 desc(
"Input JSON stream encoding"),
323 "messages delimited by --- lines, with # comment support")),
328 opt<bool> EnableTestScheme{
329 "enable-test-uri-scheme",
331 desc(
"Enable 'test:' URI scheme. Only use in lit tests"),
336 opt<Path> InputMirrorFile{
339 desc(
"Mirror all LSP input to the specified file. Useful for debugging"),
344 opt<Logger::Level> LogLevel{
347 desc(
"Verbosity of log messages written to stderr"),
348 values(clEnumValN(
Logger::Error,
"error",
"Error messages only"),
349 clEnumValN(
Logger::Info,
"info",
"High level execution tracing"),
354 opt<OffsetEncoding> ForceOffsetEncoding{
357 desc(
"Force the offsetEncoding used for character positions. " 358 "This bypasses negotiation via client capabilities"),
362 "Offsets are in UTF-16 code units")),
366 opt<bool> PrettyPrint{
369 desc(
"Pretty-print JSON output"),
379 llvm::Expected<std::string>
380 getAbsolutePath(llvm::StringRef , llvm::StringRef Body,
381 llvm::StringRef )
const override {
385 if (!Body.startswith(
"/"))
386 return llvm::make_error<llvm::StringError>(
387 "Expect URI body to be an absolute path starting with '/': " + Body,
388 llvm::inconvertibleErrorCode());
389 Body = Body.ltrim(
'/');
390 llvm::SmallVector<char, 16>
Path(Body.begin(), Body.end());
393 return std::string(
Path.begin(),
Path.end());
397 uriFromAbsolutePath(llvm::StringRef AbsolutePath)
const override {
398 llvm::StringRef Body = AbsolutePath;
399 if (!Body.consume_front(TestScheme::TestDir)) {
400 return llvm::make_error<llvm::StringError>(
401 "Path " + AbsolutePath +
" doesn't start with root " + TestDir,
402 llvm::inconvertibleErrorCode());
405 return URI(
"test",
"",
406 llvm::sys::path::convert_to_slash(Body));
410 const static char TestDir[];
414 const char TestScheme::TestDir[] =
"C:\\clangd-test";
416 const char TestScheme::TestDir[] =
"/clangd-test";
428 int main(
int argc,
char *argv[]) {
429 using namespace clang;
432 llvm::InitializeAllTargetInfos();
433 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
434 llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) {
435 OS << clang::getClangToolFullVersion(
"clangd") <<
"\n";
437 const char *FlagsEnvVar =
"CLANGD_FLAGS";
438 const char *Overview =
439 R
"(clangd is a language server that provides IDE-like features to editors. 441 It should be used via an editor plugin rather than invoked directly. For more information, see: 442 https://clang.llvm.org/extra/clangd/ 443 https://microsoft.github.io/language-server-protocol/ 445 clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. 447 llvm::cl::HideUnrelatedOptions(ClangdCategories); 448 llvm::cl::ParseCommandLineOptions(argc, argv, Overview, 449 nullptr, FlagsEnvVar);
458 if (Test || EnableTestScheme) {
459 static URISchemeRegistry::Add<TestScheme>
X(
460 "test",
"Test scheme for clangd lit tests.");
463 if (!Sync && WorkerThreadsCount == 0) {
464 llvm::errs() <<
"A number of worker threads cannot be 0. Did you mean to " 470 if (WorkerThreadsCount.getNumOccurrences())
471 llvm::errs() <<
"Ignoring -j because -sync is set.\n";
472 WorkerThreadsCount = 0;
474 if (FallbackStyle.getNumOccurrences())
475 clang::format::DefaultFallbackStyle = FallbackStyle.c_str();
478 llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
479 if (!InputMirrorFile.empty()) {
481 InputMirrorStream.emplace(InputMirrorFile, EC,
482 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
484 InputMirrorStream.reset();
485 llvm::errs() <<
"Error while opening an input mirror file: " 488 InputMirrorStream->SetUnbuffered();
495 llvm::Optional<llvm::raw_fd_ostream> TraceStream;
496 std::unique_ptr<trace::EventTracer> Tracer;
497 if (
auto *TraceFile = getenv(
"CLANGD_TRACE")) {
499 TraceStream.emplace(TraceFile, EC,
500 llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
503 llvm::errs() <<
"Error while opening trace file " << TraceFile <<
": " 510 llvm::Optional<trace::Session> TracingSession;
512 TracingSession.emplace(*Tracer);
517 if (llvm::outs().is_displayed() && llvm::errs().is_displayed())
518 llvm::errs() << Overview <<
"\n";
521 llvm::errs().SetBuffered();
525 log(
"{0}", clang::getClangToolFullVersion(
"clangd"));
527 SmallString<128> CWD;
528 if (
auto Err = llvm::sys::fs::current_path(CWD))
529 log(
"Working directory unknown: {0}", Err.message());
531 log(
"Working directory: {0}", CWD);
533 for (
int I = 0; I < argc; ++I)
534 log(
"argv[{0}]: {1}", I, argv[I]);
535 if (
auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
536 log(
"{0}: {1}", FlagsEnvVar, *EnvFlags);
540 llvm::Optional<Path> CompileCommandsDirPath;
541 if (!CompileCommandsDir.empty()) {
542 if (llvm::sys::fs::exists(CompileCommandsDir)) {
547 llvm::SmallString<128>
Path(CompileCommandsDir);
549 llvm::errs() <<
"Error while converting the relative path specified by " 550 "--compile-commands-dir to an absolute path: " 551 << EC.message() <<
". The argument will be ignored.\n";
553 CompileCommandsDirPath = Path.str();
557 <<
"Path specified by --compile-commands-dir does not exist. The " 558 "argument will be ignored.\n";
563 switch (PCHStorage) {
564 case PCHStorageFlag::Memory:
567 case PCHStorageFlag::Disk:
571 if (!ResourceDir.empty())
575 std::unique_ptr<SymbolIndex> StaticIdx;
576 std::future<void> AsyncIndexLoad;
577 if (EnableIndex && !IndexFile.empty()) {
580 StaticIdx.
reset(Placeholder =
new SwapIndex(llvm::make_unique<MemIndex>()));
581 AsyncIndexLoad = runAsync<void>([Placeholder] {
582 if (
auto Idx =
loadIndex(IndexFile,
true))
583 Placeholder->
reset(std::move(Idx));
586 AsyncIndexLoad.wait();
593 CCOpts.
Limit = LimitResults;
594 if (CompletionStyle.getNumOccurrences())
598 if (!HeaderInsertionDecorators) {
610 llvm::sys::ChangeStdinToBinary();
612 std::unique_ptr<Transport> TransportLayer;
613 if (getenv(
"CLANGD_AS_XPC_SERVICE")) {
615 log(
"Starting LSP over XPC service");
618 llvm::errs() <<
"This clangd binary wasn't built with XPC support.\n";
622 log(
"Starting LSP over stdin/stdout");
625 InputMirrorStream ? InputMirrorStream.getPointer() :
nullptr,
626 PrettyPrint, InputStyle);
630 std::mutex ClangTidyOptMu;
631 std::unique_ptr<tidy::ClangTidyOptionsProvider>
632 ClangTidyOptProvider;
633 if (EnableClangTidy) {
635 OverrideClangTidyOptions.Checks = ClangTidyChecks;
636 ClangTidyOptProvider = llvm::make_unique<tidy::FileOptionsProvider>(
641 llvm::StringRef
File) {
643 std::lock_guard<std::mutex> Lock(ClangTidyOptMu);
645 return ClangTidyOptProvider->getOptions(
File);
652 if (T.hidden() && !HiddenFeatures)
654 if (TweakList.getNumOccurrences())
655 return llvm::is_contained(TweakList, T.id());
658 llvm::Optional<OffsetEncoding> OffsetEncodingFromFlag;
660 OffsetEncodingFromFlag = ForceOffsetEncoding;
662 *TransportLayer, FSProvider, CCOpts, CompileCommandsDirPath,
663 CompileArgsFrom == FilesystemCompileArgs,
664 OffsetEncodingFromFlag, Opts);
665 llvm::set_thread_name(
"clangd.main");
666 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