diff options
-rw-r--r-- | clang-tools-extra/clangd/tool/CMakeLists.txt | 7 | ||||
-rw-r--r-- | clang-tools-extra/clangd/tool/ClangdMain.cpp | 891 | ||||
-rw-r--r-- | clang-tools-extra/clangd/tool/Opts.td | 426 |
3 files changed, 804 insertions, 520 deletions
diff --git a/clang-tools-extra/clangd/tool/CMakeLists.txt b/clang-tools-extra/clangd/tool/CMakeLists.txt index 6c21175..5477946 100644 --- a/clang-tools-extra/clangd/tool/CMakeLists.txt +++ b/clang-tools-extra/clangd/tool/CMakeLists.txt @@ -6,9 +6,16 @@ add_clang_library(clangdMain Check.cpp ) +set(LLVM_TARGET_DEFINITIONS Opts.td) +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(ClangdOptsTableGen) + add_clang_tool(clangd ClangdToolMain.cpp $<TARGET_OBJECTS:obj.clangDaemonTweaks> + + DEPENDS + ClangdOptsTableGen ) set(LLVM_LINK_COMPONENTS diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 3b08e02..c846c71 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ClangdMain.h" + #include "Check.h" #include "ClangdLSPServer.h" #include "CodeComplete.h" @@ -14,7 +15,7 @@ #include "Config.h" #include "ConfigProvider.h" #include "Feature.h" -#include "IncludeCleaner.h" +#include "Opts.inc" #include "PathMapping.h" #include "Protocol.h" #include "TidyProvider.h" @@ -22,7 +23,6 @@ #include "index/Background.h" #include "index/Index.h" #include "index/MemIndex.h" -#include "index/Merge.h" #include "index/ProjectAware.h" #include "index/remote/Client.h" #include "support/Path.h" @@ -33,7 +33,13 @@ #include "clang/Basic/Stack.h" #include "clang/Format/Format.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" @@ -42,14 +48,13 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" #include <chrono> #include <cstdlib> #include <memory> -#include <mutex> #include <optional> #include <string> -#include <thread> #include <utility> #include <vector> @@ -61,464 +66,231 @@ #include <malloc.h> #endif -namespace clang { -namespace clangd { - namespace { -using llvm::cl::cat; -using llvm::cl::CommaSeparated; -using llvm::cl::desc; -using llvm::cl::Hidden; -using llvm::cl::init; -using llvm::cl::list; -using llvm::cl::opt; -using llvm::cl::OptionCategory; -using llvm::cl::ValueOptional; -using llvm::cl::values; - -// All flags must be placed in a category, or they will be shown neither in -// --help, nor --help-hidden! -OptionCategory CompileCommands("clangd compilation flags options"); -OptionCategory Features("clangd feature options"); -OptionCategory Misc("clangd miscellaneous options"); -OptionCategory Protocol("clangd protocol and logging options"); -OptionCategory Retired("clangd flags no longer in use"); -const OptionCategory *ClangdCategories[] = {&Features, &Protocol, - &CompileCommands, &Misc, &Retired}; - -template <typename T> class RetiredFlag { - opt<T> Option; - -public: - RetiredFlag(llvm::StringRef Name) - : Option(Name, cat(Retired), desc("Obsolete flag, ignored"), Hidden, - llvm::cl::callback([Name](const T &) { - llvm::errs() - << "The flag `-" << Name << "` is obsolete and ignored.\n"; - })) {} -}; - -enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs }; -opt<CompileArgsFrom> CompileArgsFrom{ - "compile_args_from", - cat(CompileCommands), - desc("The source of compile commands"), - values(clEnumValN(LSPCompileArgs, "lsp", - "All compile commands come from LSP and " - "'compile_commands.json' files are ignored"), - clEnumValN(FilesystemCompileArgs, "filesystem", - "All compile commands come from the " - "'compile_commands.json' files")), - init(FilesystemCompileArgs), - Hidden, -}; - -opt<Path> CompileCommandsDir{ - "compile-commands-dir", - cat(CompileCommands), - desc("Specify a path to look for compile_commands.json. If path " - "is invalid, clangd will look in the current directory and " - "parent paths of each source file"), -}; - -opt<Path> ResourceDir{ - "resource-dir", - cat(CompileCommands), - desc("Directory for system clang headers"), - init(""), - Hidden, -}; - -list<std::string> QueryDriverGlobs{ - "query-driver", - cat(CompileCommands), - desc( - "Comma separated list of globs for white-listing gcc-compatible " - "drivers that are safe to execute. Drivers matching any of these globs " - "will be used to extract system includes. e.g. " - "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"), - CommaSeparated, -}; - -// FIXME: Flags are the wrong mechanism for user preferences. -// We should probably read a dotfile or similar. -opt<bool> AllScopesCompletion{ - "all-scopes-completion", - cat(Features), - desc("If set to true, code completion will include index symbols that are " - "not defined in the scopes (e.g. " - "namespaces) visible from the code completion point. Such completions " - "can insert scope qualifiers"), - init(true), -}; +#if defined(__GLIBC__) && CLANGD_MALLOC_TRIM +static constexpr unsigned MallocTrimVis = (1 << 8); +#else +static constexpr unsigned MallocTrimVis = 0; +#endif -opt<bool> ShowOrigins{ - "debug-origin", - cat(Features), - desc("Show origins of completion items"), - init(CodeCompleteOptions().ShowOrigins), - Hidden, -}; +#if CLANGD_ENABLE_REMOTE +// FIXME(kirillbobyrev): Should this be the location of compile_commands.json? +static constexpr unsigned RemoteVis = (1 << 9); +#else +static constexpr unsigned RemoteVis = 0; +#endif -opt<bool> EnableBackgroundIndex{ - "background-index", - cat(Features), - desc("Index project code in the background and persist index on disk."), - init(true), +using namespace llvm; +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), +#include "Opts.inc" +#undef OPTION }; -opt<llvm::ThreadPriority> BackgroundIndexPriority{ - "background-index-priority", - cat(Features), - desc("Thread priority for building the background index. " - "The effect of this flag is OS-specific."), - values(clEnumValN(llvm::ThreadPriority::Background, "background", - "Minimum priority, runs on idle CPUs. " - "May leave 'performance' cores unused."), - clEnumValN(llvm::ThreadPriority::Low, "low", - "Reduced priority compared to interactive work."), - clEnumValN(llvm::ThreadPriority::Default, "normal", - "Same priority as other clangd work.")), - init(llvm::ThreadPriority::Low), -}; +#define PREFIX(NAME, VALUE) \ + static constexpr StringLiteral NAME##_init[] = VALUE; \ + static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ + std::size(NAME##_init) - 1); +#include "Opts.inc" +#undef PREFIX -opt<bool> EnableClangTidy{ - "clang-tidy", - cat(Features), - desc("Enable clang-tidy diagnostics"), - init(true), +using namespace llvm::opt; +static constexpr opt::OptTable::Info InfoTable[] = { +#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), +#include "Opts.inc" +#undef OPTION }; -opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{ - "completion-parse", - cat(Features), - desc("Whether the clang-parser is used for code-completion"), - values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always", - "Block until the parser can be used"), - clEnumValN(CodeCompleteOptions::ParseIfReady, "auto", - "Use text-based completion if the parser " - "is not ready"), - clEnumValN(CodeCompleteOptions::NeverParse, "never", - "Always used text-based completion")), - init(CodeCompleteOptions().RunParser), - Hidden, +class ClangdOptTable : public llvm::opt::GenericOptTable { +public: + ClangdOptTable() : GenericOptTable(InfoTable) { + setGroupedShortOptions(true); + } }; -opt<CodeCompleteOptions::CodeCompletionRankingModel> RankingModel{ - "ranking-model", - cat(Features), - desc("Model to use to rank code-completion items"), - values(clEnumValN(CodeCompleteOptions::Heuristics, "heuristics", - "Use heuristics to rank code completion items"), - clEnumValN(CodeCompleteOptions::DecisionForest, "decision_forest", - "Use Decision Forest model to rank completion items")), - init(CodeCompleteOptions().RankingModel), - Hidden, -}; +enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs }; // FIXME: also support "plain" style where signatures are always omitted. -enum CompletionStyleFlag { Detailed, Bundled }; -opt<CompletionStyleFlag> CompletionStyle{ - "completion-style", - cat(Features), - desc("Granularity of code completion suggestions"), - values(clEnumValN(Detailed, "detailed", - "One completion item for each semantically distinct " - "completion, with full type information"), - clEnumValN(Bundled, "bundled", - "Similar completion items (e.g. function overloads) are " - "combined. Type information shown where possible")), -}; - -opt<std::string> FallbackStyle{ - "fallback-style", - cat(Features), - desc("clang-format style to apply by default when " - "no .clang-format file is found"), - init(clang::format::DefaultFallbackStyle), -}; +enum CompletionStyleFlag { Detailed, Bundled, Invalid }; +enum PCHStorageFlag { Disk, Memory }; -opt<bool> EnableFunctionArgSnippets{ - "function-arg-placeholders", - cat(Features), - desc("When disabled, completions contain only parentheses for " - "function calls. When enabled, completions also contain " - "placeholders for method parameters"), - init(CodeCompleteOptions().EnableFunctionArgSnippets), -}; +} // namespace -opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{ - "header-insertion", - cat(Features), - desc("Add #include directives when accepting code completions"), - init(CodeCompleteOptions().InsertIncludes), - values( - clEnumValN(CodeCompleteOptions::IWYU, "iwyu", - "Include what you use. " - "Insert the owning header for top-level symbols, unless the " - "header is already directly included or the symbol is " - "forward-declared"), - clEnumValN( - CodeCompleteOptions::NeverInsert, "never", - "Never insert #include directives as part of code completion")), -}; +namespace clang { +namespace clangd { -opt<bool> ImportInsertions{ - "import-insertions", - cat(Features), - desc("If header insertion is enabled, add #import directives when " - "accepting code completions or fixing includes in Objective-C code"), - init(CodeCompleteOptions().ImportInsertions), -}; +static void parseValueError(const StringRef ArgName, const StringRef Value) { + llvm::errs() << "for the " << ArgName << " option: Cannot find option named " + << Value; + exit(EXIT_FAILURE); +} -opt<bool> HeaderInsertionDecorators{ - "header-insertion-decorators", - cat(Features), - desc("Prepend a circular dot or space before the completion " - "label, depending on whether " - "an include line will be inserted or not"), - init(true), -}; +template <typename T> +static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value, + T Default) { + if (const opt::Arg *A = Args.getLastArg(ID)) { + StringRef V(A->getValue()); + if (!llvm::to_integer(V, Value, 0)) { + errs() << A->getSpelling() + ": expected an integer, but got '" + V + "'"; + exit(1); + } + } else { + Value = Default; + } +} -opt<bool> HiddenFeatures{ - "hidden-features", - cat(Features), - desc("Enable hidden features mostly useful to clangd developers"), - init(false), - Hidden, -}; +static PCHStorageFlag parsePCHStorage(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_pch_storage_EQ)) { + StringRef PCHStorageStr = Args.getLastArgValue(OPT_pch_storage_EQ); + if (PCHStorageStr.equals("disk")) + return PCHStorageFlag::Disk; + if (PCHStorageStr.equals("memory")) + return PCHStorageFlag::Memory; -opt<bool> IncludeIneligibleResults{ - "include-ineligible-results", - cat(Features), - desc("Include ineligible completion results (e.g. private members)"), - init(CodeCompleteOptions().IncludeIneligibleResults), - Hidden, -}; + parseValueError(Args.getArgString(OPT_pch_storage_EQ), PCHStorageStr); + } -RetiredFlag<bool> EnableIndex("index"); -RetiredFlag<bool> SuggestMissingIncludes("suggest-missing-includes"); -RetiredFlag<bool> RecoveryAST("recovery-ast"); -RetiredFlag<bool> RecoveryASTType("recovery-ast-type"); -RetiredFlag<bool> AsyncPreamble("async-preamble"); -RetiredFlag<bool> CollectMainFileRefs("collect-main-file-refs"); -RetiredFlag<bool> CrossFileRename("cross-file-rename"); -RetiredFlag<std::string> ClangTidyChecks("clang-tidy-checks"); -RetiredFlag<bool> InlayHints("inlay-hints"); -RetiredFlag<bool> FoldingRanges("folding-ranges"); -RetiredFlag<bool> IncludeCleanerStdlib("include-cleaner-stdlib"); - -opt<int> LimitResults{ - "limit-results", - cat(Features), - desc("Limit the number of results returned by clangd. " - "0 means no limit (default=100)"), - init(100), -}; + return PCHStorageFlag::Disk; +} -opt<int> ReferencesLimit{ - "limit-references", - cat(Features), - desc("Limit the number of references returned by clangd. " - "0 means no limit (default=1000)"), - init(1000), -}; +static JSONStreamStyle parseInputStyle(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_input_style_EQ)) { + StringRef InputStyleStr = Args.getLastArgValue(OPT_input_style_EQ); + if (InputStyleStr.equals("standard")) + return JSONStreamStyle::Standard; + if (InputStyleStr.equals("delimited")) + return JSONStreamStyle::Delimited; -opt<int> RenameFileLimit{ - "rename-file-limit", - cat(Features), - desc("Limit the number of files to be affected by symbol renaming. " - "0 means no limit (default=50)"), - init(50), -}; + parseValueError(Args.getArgString(OPT_input_style_EQ), InputStyleStr); + } -list<std::string> TweakList{ - "tweaks", - cat(Features), - desc("Specify a list of Tweaks to enable (only for clangd developers)."), - Hidden, - CommaSeparated, -}; + return JSONStreamStyle::Standard; +} -opt<unsigned> WorkerThreadsCount{ - "j", - cat(Misc), - desc("Number of async workers used by clangd. Background index also " - "uses this many workers."), - init(getDefaultAsyncThreadsCount()), -}; +static Logger::Level parseLogLevel(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_log_EQ)) { + StringRef LogLevelStr = Args.getLastArgValue(OPT_log_EQ); + if (LogLevelStr.equals("error")) + return Logger::Level::Error; + if (LogLevelStr.equals("info")) + return Logger::Level::Info; + if (LogLevelStr.equals("verbose")) + return Logger::Level::Verbose; + + parseValueError(Args.getArgString(OPT_log_EQ), LogLevelStr); + } -opt<Path> IndexFile{ - "index-file", - cat(Misc), - desc( - "Index file to build the static index. The file must have been created " - "by a compatible clangd-indexer\n" - "WARNING: This option is experimental only, and will be removed " - "eventually. Don't rely on it"), - init(""), - Hidden, -}; + return Logger::Level::Info; +} -opt<bool> Test{ - "lit-test", - cat(Misc), - desc("Abbreviation for -input-style=delimited -pretty -sync " - "-enable-test-scheme -enable-config=0 -log=verbose -crash-pragmas. " - "Also sets config options: Index.StandardLibrary=false. " - "Intended to simplify lit tests"), - init(false), - Hidden, -}; +static CodeCompleteOptions::CodeCompletionRankingModel +parseRankingModel(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_ranking_model_EQ)) { + StringRef RankingModelStr = Args.getLastArgValue(OPT_ranking_model_EQ); + if (RankingModelStr.equals("heuristics")) + return CodeCompleteOptions::Heuristics; + if (RankingModelStr.equals("decision_forest")) + return CodeCompleteOptions::DecisionForest; -opt<bool> CrashPragmas{ - "crash-pragmas", - cat(Misc), - desc("Respect `#pragma clang __debug crash` and friends."), - init(false), - Hidden, -}; + parseValueError(Args.getArgString(OPT_ranking_model_EQ), RankingModelStr); + } -opt<Path> CheckFile{ - "check", - cat(Misc), - desc("Parse one file in isolation instead of acting as a language server. " - "Useful to investigate/reproduce crashes or configuration problems. " - "With --check=<filename>, attempts to parse a particular file."), - init(""), - ValueOptional, -}; + return CodeCompleteOptions().RankingModel; +} -enum PCHStorageFlag { Disk, Memory }; -opt<PCHStorageFlag> PCHStorage{ - "pch-storage", - cat(Misc), - desc("Storing PCHs in memory increases memory usages, but may " - "improve performance"), - values( - clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"), - clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")), - init(PCHStorageFlag::Disk), -}; +static CompileArgsFrom parseCompileArgsFrom(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_compile_args_from_EQ)) { + StringRef CompileArgsFromStr = + Args.getLastArgValue(OPT_compile_args_from_EQ); + if (CompileArgsFromStr.equals("lsp")) + return CompileArgsFrom::LSPCompileArgs; + if (CompileArgsFromStr.equals("filesystem")) + return CompileArgsFrom::FilesystemCompileArgs; + + parseValueError(Args.getArgString(OPT_compile_args_from_EQ), + CompileArgsFromStr); + } -opt<bool> Sync{ - "sync", - cat(Misc), - desc("Handle client requests on main thread. Background index still uses " - "its own thread."), - init(false), - Hidden, -}; + return CompileArgsFrom::FilesystemCompileArgs; +} -opt<JSONStreamStyle> InputStyle{ - "input-style", - cat(Protocol), - desc("Input JSON stream encoding"), - values( - clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"), - clEnumValN(JSONStreamStyle::Delimited, "delimited", - "messages delimited by --- lines, with # comment support")), - init(JSONStreamStyle::Standard), - Hidden, -}; +static llvm::ThreadPriority +parseBackgroundIndexPriority(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_background_index_priority_EQ)) { + StringRef BackgroundIndexPriorityStr = + Args.getLastArgValue(OPT_background_index_priority_EQ); + if (BackgroundIndexPriorityStr.equals("background")) + return llvm::ThreadPriority::Background; + if (BackgroundIndexPriorityStr.equals("normal")) + return llvm::ThreadPriority::Default; + if (BackgroundIndexPriorityStr.equals("low")) + return llvm::ThreadPriority::Low; + + parseValueError(Args.getArgString(OPT_background_index_priority_EQ), + BackgroundIndexPriorityStr); + } -opt<bool> EnableTestScheme{ - "enable-test-uri-scheme", - cat(Protocol), - desc("Enable 'test:' URI scheme. Only use in lit tests"), - init(false), - Hidden, -}; + return llvm::ThreadPriority::Low; +} -opt<std::string> PathMappingsArg{ - "path-mappings", - cat(Protocol), - desc( - "Translates between client paths (as seen by a remote editor) and " - "server paths (where clangd sees files on disk). " - "Comma separated list of '<client_path>=<server_path>' pairs, the " - "first entry matching a given path is used. " - "e.g. /home/project/incl=/opt/include,/home/project=/workarea/project"), - init(""), -}; +static CompletionStyleFlag parseCompletionStyle(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_completion_style_EQ)) { + StringRef CompletionStyleStr = + Args.getLastArgValue(OPT_completion_style_EQ); + if (CompletionStyleStr.equals("detailed")) + return CompletionStyleFlag::Detailed; + if (CompletionStyleStr.equals("bundled")) + return CompletionStyleFlag::Bundled; + + parseValueError(Args.getArgString(OPT_completion_style_EQ), + CompletionStyleStr); + } -opt<Path> InputMirrorFile{ - "input-mirror-file", - cat(Protocol), - desc("Mirror all LSP input to the specified file. Useful for debugging"), - init(""), - Hidden, -}; + return CompletionStyleFlag::Invalid; +} -opt<Logger::Level> LogLevel{ - "log", - cat(Protocol), - desc("Verbosity of log messages written to stderr"), - values(clEnumValN(Logger::Error, "error", "Error messages only"), - clEnumValN(Logger::Info, "info", "High level execution tracing"), - clEnumValN(Logger::Debug, "verbose", "Low level details")), - init(Logger::Info), -}; +static CodeCompleteOptions::IncludeInsertion +parseHeaderInsertion(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_header_insertion_EQ)) { + StringRef HeaderInsertionStr = + Args.getLastArgValue(OPT_header_insertion_EQ); + if (HeaderInsertionStr.equals("iwyu")) + return CodeCompleteOptions::IWYU; + if (HeaderInsertionStr.equals("never")) + return CodeCompleteOptions::NeverInsert; + + parseValueError(Args.getArgString(OPT_header_insertion_EQ), + HeaderInsertionStr); + } -opt<OffsetEncoding> ForceOffsetEncoding{ - "offset-encoding", - cat(Protocol), - desc("Force the offsetEncoding used for character positions. " - "This bypasses negotiation via client capabilities"), - values( - clEnumValN(OffsetEncoding::UTF8, "utf-8", "Offsets are in UTF-8 bytes"), - clEnumValN(OffsetEncoding::UTF16, "utf-16", - "Offsets are in UTF-16 code units"), - clEnumValN(OffsetEncoding::UTF32, "utf-32", - "Offsets are in unicode codepoints")), - init(OffsetEncoding::UnsupportedEncoding), -}; + return CodeCompleteOptions().InsertIncludes; +} -opt<bool> PrettyPrint{ - "pretty", - cat(Protocol), - desc("Pretty-print JSON output"), - init(false), -}; +static CodeCompleteOptions::CodeCompletionParse +parseCodeCompletionParse(const opt::InputArgList &Args) { + if (Args.hasArg(OPT_completion_parse_EQ)) { + StringRef CompletionParseStr = + Args.getLastArgValue(OPT_completion_parse_EQ); + if (CompletionParseStr.equals("always")) + return CodeCompleteOptions::AlwaysParse; + if (CompletionParseStr.equals("auto")) + return CodeCompleteOptions::ParseIfReady; + if (CompletionParseStr.equals("never")) + return CodeCompleteOptions::NeverParse; + + parseValueError(Args.getArgString(OPT_completion_parse_EQ), + CompletionParseStr); + } -opt<bool> EnableConfig{ - "enable-config", - cat(Misc), - desc( - "Read user and project configuration from YAML files.\n" - "Project config is from a .clangd file in the project directory.\n" - "User config is from clangd/config.yaml in the following directories:\n" - "\tWindows: %USERPROFILE%\\AppData\\Local\n" - "\tMac OS: ~/Library/Preferences/\n" - "\tOthers: $XDG_CONFIG_HOME, usually ~/.config\n" - "Configuration is documented at https://clangd.llvm.org/config.html"), - init(true), -}; + return CodeCompleteOptions().RunParser; +} -opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc), - desc("Use files open in the editor when parsing " - "headers instead of reading from the disk"), - Hidden, - init(ClangdServer::Options().UseDirtyHeaders)}; - -opt<bool> PreambleParseForwardingFunctions{ - "parse-forwarding-functions", - cat(Misc), - desc("Parse all emplace-like functions in included headers"), - Hidden, - init(ParseOptions().PreambleParseForwardingFunctions), -}; +namespace { #if defined(__GLIBC__) && CLANGD_MALLOC_TRIM -opt<bool> EnableMallocTrim{ - "malloc-trim", - cat(Misc), - desc("Release memory periodically via malloc_trim(3)."), - init(true), -}; - -std::function<void()> getMemoryCleanupFunction() { +std::function<void()> getMemoryCleanupFunction(bool EnableMallocTrim) { if (!EnableMallocTrim) return nullptr; // Leave a few MB at the top of the heap: it is insignificant @@ -530,52 +302,11 @@ std::function<void()> getMemoryCleanupFunction() { }; } #else -std::function<void()> getMemoryCleanupFunction() { return nullptr; } -#endif - -#if CLANGD_ENABLE_REMOTE -opt<std::string> RemoteIndexAddress{ - "remote-index-address", - cat(Features), - desc("Address of the remote index server"), -}; - -// FIXME(kirillbobyrev): Should this be the location of compile_commands.json? -opt<std::string> ProjectRoot{ - "project-root", - cat(Features), - desc("Path to the project root. Requires remote-index-address to be set."), -}; +std::function<void()> getMemoryCleanupFunction(bool EnableMallocTrim) { + return nullptr +} #endif -// These will never be shown in --help, ClangdMain doesn't list the category. -// See clang-tools-extra/clangd/tool/Check.cpp for more information. -llvm::cl::opt<std::string> CheckTidyTime{ - "check-tidy-time", - llvm::cl::desc("Print the overhead of checks matching this glob"), - llvm::cl::init("")}; -llvm::cl::opt<std::string> CheckFileLines{ - "check-lines", - llvm::cl::desc( - "Limits the range of tokens in -check file on which " - "various features are tested. Example --check-lines=3-7 restricts " - "testing to lines 3 to 7 (inclusive) or --check-lines=5 to restrict " - "to one line. Default is testing entire file."), - llvm::cl::init("")}; -llvm::cl::opt<bool> CheckLocations{ - "check-locations", - llvm::cl::desc( - "Runs certain features (e.g. hover) at each point in the file. " - "Somewhat slow."), - llvm::cl::init(true)}; -llvm::cl::opt<bool> CheckCompletion{ - "check-completion", - llvm::cl::desc("Run code-completion at each point (slow)"), - llvm::cl::init(false)}; -llvm::cl::opt<bool> CheckWarnings{ - "check-warnings", llvm::cl::desc("Print warnings as well as errors"), - llvm::cl::init(false)}; - /// Supports a test URI scheme with relaxed constraints for lit tests. /// The path in a test URI will be combined with a platform-specific fake /// directory to form an absolute path. For example, test:///a.cpp is resolved @@ -653,6 +384,14 @@ loadExternalIndex(const Config::ExternalIndexSpec &External, llvm_unreachable("Invalid ExternalIndexKind."); } +struct FlagsConfigProviderOpts { + Path CompileCommandsDir; + std::string IndexFile; + bool EnableBackgroundIndex; + std::optional<bool> AllScopesCompletion; + bool LitTest; +}; + class FlagsConfigProvider : public config::Provider { private: config::CompiledFragment Frag; @@ -664,20 +403,22 @@ private: } public: - FlagsConfigProvider() { + FlagsConfigProvider(FlagsConfigProviderOpts &Opts) { std::optional<Config::CDBSearchSpec> CDBSearch; std::optional<Config::ExternalIndexSpec> IndexSpec; std::optional<Config::BackgroundPolicy> BGPolicy; // If --compile-commands-dir arg was invoked, check value and override // default path. - if (!CompileCommandsDir.empty()) { - if (llvm::sys::fs::exists(CompileCommandsDir)) { + if (!Opts.CompileCommandsDir.empty()) { + elog("I must be printed elog"); + log("I am being printed log."); + if (llvm::sys::fs::exists(Opts.CompileCommandsDir)) { // We support passing both relative and absolute paths to the // --compile-commands-dir argument, but we assume the path is absolute // in the rest of clangd so we make sure the path is absolute before // continuing. - llvm::SmallString<128> Path(CompileCommandsDir); + llvm::SmallString<128> Path(Opts.CompileCommandsDir); if (std::error_code EC = llvm::sys::fs::make_absolute(Path)) { elog("Error while converting the relative path specified by " "--compile-commands-dir to an absolute path: {0}. The argument " @@ -687,14 +428,15 @@ public: CDBSearch = {Config::CDBSearchSpec::FixedDir, Path.str().str()}; } } else { + llvm::errs() << "Path does not exists 'compilecommandsdir'\n"; elog("Path specified by --compile-commands-dir does not exist. The " "argument will be ignored."); } } - if (!IndexFile.empty()) { + if (!Opts.IndexFile.empty()) { Config::ExternalIndexSpec Spec; Spec.Kind = Spec.File; - Spec.Location = IndexFile; + Spec.Location = Opts.IndexFile; IndexSpec = std::move(Spec); } #if CLANGD_ENABLE_REMOTE @@ -708,7 +450,7 @@ public: BGPolicy = Config::BackgroundPolicy::Skip; } #endif - if (!EnableBackgroundIndex) { + if (!Opts.EnableBackgroundIndex) { BGPolicy = Config::BackgroundPolicy::Skip; } @@ -719,10 +461,10 @@ public: C.Index.External = *IndexSpec; if (BGPolicy) C.Index.Background = *BGPolicy; - if (AllScopesCompletion.getNumOccurrences()) - C.Completion.AllScopes = AllScopesCompletion; + if (Opts.AllScopesCompletion) + C.Completion.AllScopes = Opts.AllScopesCompletion.value(); - if (Test) + if (Opts.LitTest) C.Index.StandardLibrary = false; return true; }; @@ -765,34 +507,71 @@ It should be used via an editor plugin rather than invoked directly. For more in clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. )"; - llvm::cl::HideUnrelatedOptions(ClangdCategories); - llvm::cl::ParseCommandLineOptions(argc, argv, Overview, - /*Errs=*/nullptr, FlagsEnvVar); - if (Test) { - if (!Sync.getNumOccurrences()) - Sync = true; - if (!CrashPragmas.getNumOccurrences()) - CrashPragmas = true; + + const StringRef ToolName = argv[0]; + BumpPtrAllocator A; + StringSaver Saver(A); + ClangdOptTable Tbl; + Tbl.setInitialOptionsFromEnvironment(FlagsEnvVar); + opt::InputArgList Args = + Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { + llvm::errs() << Msg << '\n'; + std::exit(1); + }); + + if (Args.hasArg(OPT_help) || Args.hasArg(OPT_help_hidden)) { + Tbl.printHelp( + llvm::outs(), (ToolName + " [options]").str().c_str(), Overview, + Args.hasArg(OPT_help_hidden), false, + llvm::opt::Visibility(MallocTrimVis | RemoteVis | DefaultVis)); + std::exit(0); + } + + if (Args.hasArg(OPT_version)) { + outs() << ToolName << '\n'; + cl::PrintVersionMessage(); + exit(0); + } + + bool Sync = Args.hasFlag(OPT_sync, OPT_no_sync, Args.hasArg(OPT_lit_test)); + bool CrashPragmas = Args.hasArg(OPT_crash_pragmas); + + JSONStreamStyle InputStyle = parseInputStyle(Args); + Logger::Level LogLevel = parseLogLevel(Args); + + bool PrettyPrint = Args.hasArg(OPT_pretty); + bool EnableConfig = + Args.hasFlag(OPT_enable_config, OPT_no_enable_config, true); + + bool EnableBackgroundIndex = + Args.hasFlag(OPT_background_index, OPT_no_background_index, true); + + if (Args.hasArg(OPT_lit_test)) { + CrashPragmas = true; InputStyle = JSONStreamStyle::Delimited; LogLevel = Logger::Verbose; PrettyPrint = true; // Disable config system by default to avoid external reads. - if (!EnableConfig.getNumOccurrences()) + if (!Args.hasArg(OPT_enable_config)) EnableConfig = false; // Disable background index on lit tests by default to prevent disk writes. - if (!EnableBackgroundIndex.getNumOccurrences()) + if (!Args.hasArg(OPT_background_index)) EnableBackgroundIndex = false; // Ensure background index makes progress. else if (EnableBackgroundIndex) BackgroundQueue::preventThreadStarvationInTests(); } - if (Test || EnableTestScheme) { + if (Args.hasArg(OPT_lit_test) || Args.hasArg(OPT_enable_test_uri_scheme)) { static URISchemeRegistry::Add<TestScheme> X( "test", "Test scheme for clangd lit tests."); } if (CrashPragmas) allowCrashPragmasForTest(); + unsigned int WorkerThreadsCount; + parseIntArg(Args, OPT_j_EQ, WorkerThreadsCount, + getDefaultAsyncThreadsCount()); + if (!Sync && WorkerThreadsCount == 0) { llvm::errs() << "A number of worker threads cannot be 0. Did you mean to " "specify -sync?"; @@ -800,15 +579,19 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var } if (Sync) { - if (WorkerThreadsCount.getNumOccurrences()) + if (Args.hasArg(OPT_j_EQ)) llvm::errs() << "Ignoring -j because -sync is set.\n"; WorkerThreadsCount = 0; } - if (FallbackStyle.getNumOccurrences()) - clang::format::DefaultFallbackStyle = FallbackStyle.c_str(); + + if (Args.hasArg(OPT_fallback_style_EQ)) + clang::format::DefaultFallbackStyle = + Args.getLastArgValue(OPT_fallback_style_EQ).str().c_str(); // Validate command line arguments. std::optional<llvm::raw_fd_ostream> InputMirrorStream; + const std::string InputMirrorFile( + Args.getLastArgValue(OPT_input_mirror_file_EQ, "")); if (!InputMirrorFile.empty()) { std::error_code EC; InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC, @@ -822,6 +605,8 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var } } + CodeCompleteOptions::CodeCompletionRankingModel RankingModel = + parseRankingModel(Args); #if !CLANGD_DECISION_FOREST if (RankingModel == clangd::CodeCompleteOptions::DecisionForest) { llvm::errs() << "Clangd was compiled without decision forest support.\n"; @@ -860,7 +645,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var // it's somewhat likely they're confused about how to use clangd. // Show them the help overview, which explains. if (llvm::outs().is_displayed() && llvm::errs().is_displayed() && - !CheckFile.getNumOccurrences()) + !Args.hasArg(OPT_check_EQ)) llvm::errs() << Overview << "\n"; // Use buffered stream to stderr (we still flush each log message). Unbuffered // stream can cause significant (non-deterministic) latency for the logger. @@ -886,8 +671,11 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var log("{0}: {1}", FlagsEnvVar, *EnvFlags); ClangdLSPServer::Options Opts; + + CompileArgsFrom CompileArgsFrom = parseCompileArgsFrom(Args); Opts.UseDirBasedCDB = (CompileArgsFrom == FilesystemCompileArgs); + const PCHStorageFlag PCHStorage = parsePCHStorage(Args); switch (PCHStorage) { case PCHStorageFlag::Memory: Opts.StorePreamblesInMemory = true; @@ -896,11 +684,21 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.StorePreamblesInMemory = false; break; } + + StringRef ResourceDir = Args.getLastArgValue(OPT_resource_dir_EQ); if (!ResourceDir.empty()) Opts.ResourceDir = ResourceDir; + Opts.BuildDynamicSymbolIndex = true; std::vector<std::unique_ptr<SymbolIndex>> IdxStack; -#if CLANGD_ENABLE_REMOTE + + const StringRef IndexFile = Args.getLastArgValue(OPT_index_file_EQ, ""); + +#if !CLANGD_ENABLE_REMOTE + const StringRef RemoteIndexAddress = + Args.getLastArgValue(OPT_remote_index_address_EQ, ""); + const StringRef ProjectRoot = + Args.getLastArgValue(OPT_remote_index_address_EQ, ""); if (RemoteIndexAddress.empty() != ProjectRoot.empty()) { llvm::errs() << "remote-index-address and project-path have to be " "specified at the same time."; @@ -916,27 +714,38 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var } #endif Opts.BackgroundIndex = EnableBackgroundIndex; - Opts.BackgroundIndexPriority = BackgroundIndexPriority; - Opts.ReferencesLimit = ReferencesLimit; - Opts.Rename.LimitFiles = RenameFileLimit; + Opts.BackgroundIndexPriority = parseBackgroundIndexPriority(Args); + parseIntArg(Args, OPT_limit_references_EQ, Opts.ReferencesLimit, + size_t(1000)); + parseIntArg(Args, OPT_rename_file_limit_EQ, Opts.Rename.LimitFiles, + size_t(50)); auto PAI = createProjectAwareIndex(loadExternalIndex, Sync); Opts.StaticIndex = PAI.get(); Opts.AsyncThreadsCount = WorkerThreadsCount; - Opts.MemoryCleanup = getMemoryCleanupFunction(); + Opts.MemoryCleanup = getMemoryCleanupFunction( + Args.hasFlag(OPT_malloc_trim, OPT_no_malloc_trim, true)); + + Opts.CodeComplete.IncludeIneligibleResults = + Args.hasArg(OPT_include_ineligible_results); - Opts.CodeComplete.IncludeIneligibleResults = IncludeIneligibleResults; - Opts.CodeComplete.Limit = LimitResults; - if (CompletionStyle.getNumOccurrences()) + parseIntArg(Args, OPT_limit_results_EQ, Opts.CodeComplete.Limit, size_t(100)); + if (Args.hasArg(OPT_completion_style_EQ)) { + CompletionStyleFlag CompletionStyle = parseCompletionStyle(Args); Opts.CodeComplete.BundleOverloads = CompletionStyle != Detailed; - Opts.CodeComplete.ShowOrigins = ShowOrigins; - Opts.CodeComplete.InsertIncludes = HeaderInsertion; - Opts.CodeComplete.ImportInsertions = ImportInsertions; - if (!HeaderInsertionDecorators) { + } + Opts.CodeComplete.ShowOrigins = Args.hasArg(OPT_debug_origin); + Opts.CodeComplete.InsertIncludes = parseHeaderInsertion(Args); + Opts.CodeComplete.ImportInsertions = + Args.hasFlag(OPT_import_insertions, OPT_no_import_insertions, true); + + if (!Args.hasFlag(OPT_header_insertion_decorators, + OPT_no_header_insertion_decorators, true)) { Opts.CodeComplete.IncludeIndicator.Insert.clear(); Opts.CodeComplete.IncludeIndicator.NoInsert.clear(); } - Opts.CodeComplete.EnableFunctionArgSnippets = EnableFunctionArgSnippets; - Opts.CodeComplete.RunParser = CodeCompletionParse; + Opts.CodeComplete.EnableFunctionArgSnippets = Args.hasFlag( + OPT_function_arg_placeholders, OPT_no_function_arg_placeholders, true); + Opts.CodeComplete.RunParser = parseCodeCompletionParse(Args); Opts.CodeComplete.RankingModel = RankingModel; RealThreadsafeFS TFS; @@ -955,7 +764,24 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var elog("Couldn't determine user config file, not loading"); } } - ProviderStack.push_back(std::make_unique<FlagsConfigProvider>()); + + FlagsConfigProviderOpts FlagsProviderOpts{ + Args.getLastArgValue(OPT_compile_commands_dir_EQ).str(), + Args.getLastArgValue(OPT_index_file_EQ).str(), + Args.hasFlag(OPT_background_index, OPT_no_background_index, true), + {}, + Args.hasArg(OPT_lit_test), + }; + + if (Args.hasArg(OPT_all_scopes_completion) || + Args.hasArg(OPT_no_all_scopes_completion)) { + FlagsProviderOpts.AllScopesCompletion = std::make_optional( + Args.hasFlag(OPT_all_scopes_completion, OPT_no_all_scopes_completion, + CodeCompleteOptions().AllScopes)); + } + + ProviderStack.push_back( + std::make_unique<FlagsConfigProvider>(FlagsProviderOpts)); std::vector<const config::Provider *> ProviderPointers; for (const auto &P : ProviderStack) ProviderPointers.push_back(P.get()); @@ -964,7 +790,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var // Create an empty clang-tidy option. TidyProvider ClangTidyOptProvider; - if (EnableClangTidy) { + if (Args.hasFlag(OPT_clang_tidy, OPT_no_clang_tidy, true)) { std::vector<TidyProvider> Providers; Providers.reserve(4 + EnableConfig); Providers.push_back(provideEnvironment()); @@ -976,22 +802,44 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var ClangTidyOptProvider = combine(std::move(Providers)); Opts.ClangTidyProvider = ClangTidyOptProvider; } - Opts.UseDirtyHeaders = UseDirtyHeaders; - Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions; - Opts.ImportInsertions = ImportInsertions; - Opts.QueryDriverGlobs = std::move(QueryDriverGlobs); + Opts.UseDirtyHeaders = + Args.hasFlag(OPT_use_dirty_headers, OPT_no_use_dirty_headers, + ClangdServer::Options().UseDirtyHeaders); + + Opts.PreambleParseForwardingFunctions = Args.hasFlag( + OPT_parse_forwarding_functions, OPT_no_parse_forwarding_functions, + ParseOptions().PreambleParseForwardingFunctions); + + Opts.ImportInsertions = + Args.hasFlag(OPT_import_insertions, OPT_no_import_insertions, true); + + Opts.QueryDriverGlobs = Args.getAllArgValues(OPT_query_driver_EQ); + + const bool HiddenFeatures = Args.hasArg(OPT_hidden_features); + std::vector<std::string> TweakList = Args.getAllArgValues(OPT_tweaks_EQ); + Opts.TweakFilter = [&](const Tweak &T) { if (T.hidden() && !HiddenFeatures) return false; - if (TweakList.getNumOccurrences()) + if (!TweakList.empty()) return llvm::is_contained(TweakList, T.id()); return true; }; + + OffsetEncoding ForceOffsetEncoding = + StringSwitch<OffsetEncoding>( + Args.getLastArgValue(OPT_offset_encoding_EQ, "")) + .Case("utf-8", OffsetEncoding::UTF8) + .Case("utf-16", OffsetEncoding::UTF16) + .Case("utf-32", OffsetEncoding::UTF32) + .Default(OffsetEncoding::UnsupportedEncoding); + if (ForceOffsetEncoding != OffsetEncoding::UnsupportedEncoding) Opts.Encoding = ForceOffsetEncoding; - if (CheckFile.getNumOccurrences()) { + if (Args.hasArg(OPT_check_EQ)) { llvm::SmallString<256> Path; + StringRef CheckFile = Args.getLastArgValue(OPT_check_EQ); if (auto Error = llvm::sys::fs::real_path(CheckFile, Path, /*expand_tilde=*/true)) { elog("Failed to resolve path {0}: {1}", CheckFile, Error.message()); @@ -1000,13 +848,15 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var log("Entering check mode (no LSP server)"); ClangdCheckOptions CheckOpts; - if (CheckTidyTime.getNumOccurrences()) - CheckOpts.CheckTidyTime = std::make_optional(CheckTidyTime.ValueStr); + if (Args.hasArg(OPT_check_tidy_time_EQ)) + CheckOpts.CheckTidyTime = + std::make_optional(Args.getLastArgValue(OPT_check_tidy_time_EQ)); - CheckOpts.CheckFileLines = CheckFileLines; - CheckOpts.CheckCompletion = CheckCompletion; - CheckOpts.CheckLocations = CheckLocations; - CheckOpts.CheckWarnings = CheckWarnings; + CheckOpts.CheckFileLines = Args.getLastArgValue(OPT_check_file_lines_EQ); + CheckOpts.CheckCompletion = Args.hasArg(OPT_check_completion); + CheckOpts.CheckLocations = + Args.hasFlag(OPT_check_locations, OPT_no_check_locations, true); + CheckOpts.CheckWarnings = Args.hasArg(OPT_check_warnings); return check(Path, TFS, Opts, CheckOpts) ? 0 @@ -1031,8 +881,9 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var stdin, llvm::outs(), InputMirrorStream ? &*InputMirrorStream : nullptr, PrettyPrint, InputStyle); } - if (!PathMappingsArg.empty()) { - auto Mappings = parsePathMappings(PathMappingsArg); + if (Args.hasArg(OPT_path_mappings_EQ)) { + auto Mappings = + parsePathMappings(Args.getLastArgValue(OPT_path_mappings_EQ)); if (!Mappings) { elog("Invalid -path-mappings: {0}", Mappings.takeError()); return 1; diff --git a/clang-tools-extra/clangd/tool/Opts.td b/clang-tools-extra/clangd/tool/Opts.td new file mode 100644 index 0000000..c92a291 --- /dev/null +++ b/clang-tools-extra/clangd/tool/Opts.td @@ -0,0 +1,426 @@ +include "llvm/Option/OptParser.td" + +class F<string letter, string help> : Flag<["-"], letter>, HelpText<help>; +class FF<string name, string help> : Flag<["-", "--"], name>, HelpText<help>; + +multiclass Eq<string name, string help> { + def NAME #_EQ : Joined<["-", "--"], name #"=">, HelpText<help>; + def : Separate<["-", "--"], name>, Alias<!cast<Joined>(NAME #_EQ)>; +} + +multiclass B<string name, string help1, string help2> { + def NAME: Flag<["-" ,"--"], name>, HelpText<help1>; + def no_# NAME: Flag<["-", "--"], "no-" # name>, HelpText<help2>; +} + +def grp_generic: OptionGroup<"Generic options">, + HelpText<"Generic Options">; + +def grp_compile_commands: OptionGroup<"Compile commands">, + HelpText<"clangd compilation flags options">; + +def grp_features: OptionGroup<"Features">, + HelpText<"clangd feature options">; + +def grp_misc: OptionGroup<"Misc">, + HelpText<"clangd miscellaneaous options">; + +def grp_protocol: OptionGroup<"Protocol">, + HelpText<"clangd protocol and logging options">; + +def grp_retired: OptionGroup<"Retired">, + HelpText<"clangd flags no longer in use">; + +def grp_compat_alias: OptionGroup<"Compatibility Aliases">, + HelpText<"compatibility aliases">; + +multiclass Retired<string name> { + def : Joined<["-", "--"], name#"=">, HelpText<"Obsolete flag, ignored">, Group<grp_retired>, Flags<[HelpHidden]>; + def : Flag<["-", "--"], name>, HelpText<"Obsolete flag, ignored">, Group<grp_retired>, Flags<[HelpHidden]>; +} + +def help : FF<"help", "Display available options (--help-hidden for more)">, Group<grp_generic>; +def help_hidden : FF<"help-hidden", "Display hidden options">, Group<grp_generic>, Flags<[HelpHidden]>; +def : F<"h", "Alias for --help">, Alias<help>, Group<grp_generic>; +def version : FF<"version", "Display the version of this program">, Group<grp_generic>; +def : F<"v", "Alias for --version">, Alias<version>, Group<grp_generic>; + +defm compile_args_from : + Eq<"compile_args_from", "The source of compile commands." + "Supported values:\n" + " lsp: All compile commands come from LSP and 'compile_commands.json' files are ignored\n" + " filesystem: All compile commands come from the 'compile_commands.json' files">, + Group<grp_compile_commands>, + MetaVarName<"<value>">, + Values<"lsp,filesystem">, + Flags<[HelpHidden]>; + +defm compile_commands_dir : + Eq<"compile-commands-dir", + "Specify a path to look for compile_commands.json. If path " + "is invalid, clangd will look in the current directory and " + "parent paths of each source file">, + MetaVarName<"<string>">, + Group<grp_compile_commands>; + +defm resource_dir : + Eq<"resource-dir", "Directory for system clang headers">, + Group<grp_compile_commands>, + MetaVarName<"<string>">, + Flags<[HelpHidden]>; + +def query_driver_EQ : + CommaJoined<["-", "--"], "query-driver=">, + HelpText<"Comma separated list of globs for white-listing gcc-compatible " + "drivers that are safe to execute. Drivers matching any of these globs " + "will be used to extract system includes. e.g. " + "/usr/bin/**/clang-*,/path/to/repo/**/g++-*">, + MetaVarName<"<string>">, + Group<grp_compile_commands>; + +defm all_scopes_completion : + B<"all-scopes-completion", "Code completion will include index symbols that are " + "not defined in the scopes (e.g. namespaces) visible from the code completion point. " + "Such completions can insert scope qualifiers", + "Code completion won't include index symbols that are " + "not defined in the scopes visible from the code completion point.">, + Group<grp_features>; + +def debug_origin : + FF<"debug-origin", "Show origins of completion items">, + Group<grp_features>, + Flags<[HelpHidden]>; + +defm background_index : + B<"background-index","Index project code in the background and persist index on disk.", + "Don't index project code in the backgroud.">, + Group<grp_features>; + +defm background_index_priority : + Eq<"background-index-priority", "Thread priority for building the background index. " + "The effect of this flag is OS-specific.\n" + "Supported Values:\n" + " background: Minimum priority, runs on idle CPUs. May leave 'performance' cores unused.\n" + " low: Reduced priority compared to interactive work.\n" + " normal: Reduced priority compared to interactive work." >, + Values<"background,low,normal">, + Group<grp_features>; + +defm clang_tidy : + B<"clang-tidy", "Enable clang-tidy diagnostics, enabled by default.", "Disable clang-tidy diagnostics.">, + Group<grp_features>; + +defm completion_parse : + Eq<"completion-parse", + "Whether the clang-parser is used for code-completion\n" + "Supported Values:\n" + " always: Block until the parser can be used\n" + " auto: Use text-based completion if the parser is not ready\n" + " never: Always used text-based completion">, + Values<"always,auto,never">, + Group<grp_features>, + Flags<[HelpHidden]>; + +defm ranking_model : + Eq<"ranking-model", + "Model to use to rank code-completion items.\n" + "Supported values:\n" + " heuristics: Use heuristics to rank code completion items\n" + " decision_forest: Use Decision Forest model to rank completion items">, + Values<"heuristics,decision_forest">, + Group<grp_features>, + Flags<[HelpHidden]>; + +defm completion_style : + Eq<"completion-style", + "Granularity of code completion suggestions\n" + "Supported values:\n" + " detailed: One completion item for each semantically distinct completion, with full type information\n" + " bundled: Similar completion items (e.g. function overloads) are combined. Type information shown where possible">, + Values<"detailed,bundled">, + Group<grp_features>; + +defm fallback_style : + Eq<"fallback-style", "clang-format style to apply by default when no .clang-format file is found">, + Group<grp_features>; + +defm function_arg_placeholders : + B<"function-arg-placeholders", "Completions also contain placeholders for " + "method parameters (enabled by default)", + "Completions contain only parentheses for function calls.">, + Group<grp_features>; + +defm header_insertion : + Eq<"header-insertion", + "Add #include directives when accepting code completions\n" + "Supported values:\n" + " iwyu: Include what you use. Insert the owning header for top-level symbols, unless the" + " header is already directly included or the symbol is forward-declared\n" + " never: Never insert #include directives as part of code completion">, + Values<"iwyu,never">, + Group<grp_features>; + +defm import_insertions : + B<"import-insertions", "Add #import directives when accepting code completions " + "or fixing includes in Objective-C code (enabled by default)", + "Do not add #import directives when accepting code completions or fixing includes " + "in Objective-C code">, + Group<grp_features>; + +defm header_insertion_decorators : + B<"header-insertion-decorators", "Prepend a circular dot or space before the completion " + "label, depending on whether an include line will be inserted or not (enabled by default).", + "Do not prepend a circular dot or space before the completion label.">, + Group<grp_features>; + +def hidden_features : + FF<"hidden-features", "Enable hidden features mostly useful to clangd developers">, + Group<grp_features>, + Flags<[HelpHidden]>; + +def include_ineligible_results : + FF<"include-ineligible-results", "Include ineligible completion results (e.g. private members)">, + Group<grp_features>, + Flags<[HelpHidden]>; + +defm limit_results : + Eq<"limit-results", "Limit the number of results returned by clangd. 0 means no limit (default=100)">, + Group<grp_features>; + +defm limit_references : + Eq<"limit-references", "Limit the number of references returned by clangd. 0 means no limit (default=1000)">, + Group<grp_features>; + +defm rename_file_limit : + Eq<"rename-file-limit", "Limit the number of files to be affected by symbol renaming. 0 means no limit (default=50)">, + Group<grp_features>; + +def tweaks_EQ : + CommaJoined<["-", "--"], "tweaks=">, + HelpText<"Specify a list of Tweaks to enable (only for clangd developers).">, + Group<grp_features>, + Flags<[HelpHidden]>; + +defm j : + Eq<"j", "Number of async workers used by clangd. Background index also uses this many workers.">, + Group<grp_misc>; + +defm index_file : + Eq<"index-file", "Index file to build the static index. The file must have been created " + "by a compatible clangd-indexer\n" + "WARNING: This option is experimental only, and will be removed " + "eventually. Don't rely on it">, + Group<grp_misc>, + Flags<[HelpHidden]>; + +def lit_test : + FF<"lit-test", "Abbreviation for -input-style=delimited -pretty -sync " + "-enable-test-scheme -enable-config=0 -log=verbose -crash-pragmas. " + "Also sets config options: Index.StandardLibrary=false. " + "Intended to simplify lit tests">, + Group<grp_misc>, + Flags<[HelpHidden]>; + +def crash_pragmas : + FF<"crash-pragmas", "Respect `#pragma clang __debug crash` and friends.">, + Group<grp_misc>, + Flags<[HelpHidden]>; + +defm check : Eq<"check", "Parse one file in isolation instead of acting as a language server. " + "Useful to investigate/reproduce crashes or configuration problems. " + "With --check=<filename>, attempts to parse a particular file.">, + Group<grp_misc>; + +defm pch_storage : Eq<"pch-storage", + "Storing PCHs in memory increases memory usages, but may improve performance\n" + "Supported values:\n" + " disk: store PCHs on disk\n" + " memory: store PCHs in memory">, + MetaVarName<"<value>">, + Group<grp_misc>; + +defm sync : + B<"sync", "Handle client requests on main thread. Background index still uses its own thread.", + "Do not handle client requests on main thread.">, + Group<grp_misc>, + Flags<[HelpHidden]>; + +defm input_style : + Eq<"input-style", + "Input JSON stream encoding.\n" + "Supported values:\n" + " standard: usual LSP protocol\n" + " delimited: messages delimited by --- lines, with # comment support">, + Values<"standard,delimited">, + MetaVarName<"<value>">, + Group<grp_protocol>, + Flags<[HelpHidden]>; + +def enable_test_uri_scheme : + FF<"enable-test-uri-scheme", "Enable 'test:' URI scheme. Only use in lit tests">, + Group<grp_protocol>, + Flags<[HelpHidden]>; + +defm path_mappings : Eq<"path-mappings", "Translates between client paths (as seen by a remote editor) and " + "server paths (where clangd sees files on disk). " + "Comma separated list of '<client_path>=<server_path>' pairs, the " + "first entry matching a given path is used. " + "e.g. /home/project/incl=/opt/include,/home/project=/workarea/project">, + Group<grp_protocol>; + +defm input_mirror_file : + Eq<"input-mirror-file", "Mirror all LSP input to the specified file. Useful for debugging">, + Group<grp_protocol>, + Flags<[HelpHidden]>; + +defm log : + Eq<"log", + "Verbosity of log messages written to stderr\n" + "Supported values:\n" + " error: Error messages only\n" + " info: High level execution tracing\n" + " verbose: Low level details">, + Values<"error,info,verbose">, + MetaVarName<"<value>">, + Group<grp_protocol>; + +defm offset_encoding : + Eq<"offset-encoding", + "Force the offsetEncoding used for character positions. This bypasses negotiation via client capabilities\n" + "Supported values:\n" + " utf-8: Offsets are in UTF-8 bytes\n" + " utf-16: Offsets are in UTF-16 code units\n" + " utf-32: Offsets are in unicode codepoints">, + Values<"utf-8,utf-16,utf-32">, + MetaVarName<"<value>">, + Group<grp_protocol>; + +def pretty : FF<"pretty", "Pretty-print JSON output">, Group<grp_protocol>; + +defm enable_config : + B<"enable-config", + "Read user and project configuration from YAML files.\n" + "Project config is from a .clangd file in the project directory.\n" + "User config is from clangd/config.yaml in the following directories:\n" + " Windows: %USERPROFILE%\\AppData\\Local\n" + " Mac OS: ~/Library/Preferences/\n" + " Others: $XDG_CONFIG_HOME, usually ~/.config\n" + "Configuration is documented at https://clangd.llvm.org/config.html", + "Do not read user and project configuration form YAML files.">, + Group<grp_misc>; + +defm use_dirty_headers : + B<"use-dirty-headers", + "Use files open in the editor when parsing headers instead of reading from the disk", + "Do not Use files open in the editor when parsing headers instead of reading from the disk">, + Group<grp_misc>, + Flags<[HelpHidden]>; + +defm parse_forwarding_functions : + B<"parse-forwarding-functions", + "Parse all emplace-like functions in included headers.", + "Do not parse all emplace-like functions in included headers.">, + Group<grp_misc>, + Flags<[HelpHidden]>; + +def MallocTrimVis: OptionVisibility; + +defm malloc_trim : + B<"malloc-trim", + "Release memory periodically via malloc_trim(3) enabled by default.", + "Do not use malloc_trim(3) to release memory periodically.">, + Group<grp_misc>, + Visibility<[MallocTrimVis]>; + +def RemoteVis: OptionVisibility; + +defm remote_index_address : + Eq<"remote-index-address", "Address of the remote index server">, + Group<grp_features>, + Visibility<[RemoteVis]>; + +defm project_root : + Eq<"project-root", "Path to the project root. Requires remote-index-address to be set.">, + Group<grp_features>, + Visibility<[RemoteVis]>; + +defm : Retired<"index">; +defm : Retired<"suggest-missing-includes">; +defm : Retired<"recovery-ast">; +defm : Retired<"recovery-ast-type">; +defm : Retired<"async-preamble">; +defm : Retired<"collect-main-file-refs">; +defm : Retired<"cross-file-rename">; +defm : Retired<"clang-tidy-checks">; +defm : Retired<"inlay-hints">; +defm : Retired<"folding-ranges">; +defm : Retired<"include-cleaner-stdlib">; + +// Compatibility aliases +def : Flag<["--", "-"], "all-scopes-completion=true">, Alias<all_scopes_completion>, HelpText<"Alias for --all-scopes-completion">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "all-scopes-completion=false">, Alias<no_all_scopes_completion>, HelpText<"Alias for --no-all-scopes-completion">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "all-scopes-completion=0">, Alias<no_all_scopes_completion>, HelpText<"Alias for --no-all-scopes-completion">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +def : Flag<["--", "-"], "background-index=true">, Alias<background_index>, HelpText<"Alias for --background-index">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "background-index=false">, Alias<no_background_index>, HelpText<"Alias for --no-background-index">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "background-index=0">, Alias<no_background_index>, HelpText<"Alias for --no-background-index">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +def : Flag<["--", "-"], "clang-tidy=true">, Alias<clang_tidy>, HelpText<"Alias for --clang-tidy">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "clang-tidy=false">, Alias<no_clang_tidy>, HelpText<"Alias for --no-clang-tidy">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "clang-tidy=0">, Alias<no_clang_tidy>, HelpText<"Alias for --no-clang-tidy">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +def : Flag<["--", "-"], "function-arg-placeholders=true">, Alias<function_arg_placeholders>, HelpText<"Alias for --function-arg-placeholders">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "function-arg-placeholders=false">, Alias<no_function_arg_placeholders>, HelpText<"Alias for --no-function-arg-placeholders">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "function-arg-placeholders=0">, Alias<no_function_arg_placeholders>, HelpText<"Alias for --no-function-arg-placeholders">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +def : Flag<["--", "-"], "enable-config=true">, Alias<enable_config>, HelpText<"Alias for --enable-config">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "enable-config=false">, Alias<no_enable_config>, HelpText<"Alias for --no-enable-config">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "enable-config=0">, Alias<no_enable_config>, HelpText<"Alias for --no-enable-config">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +def : Flag<["--", "-"], "use-dirty-headers=true">, Alias<use_dirty_headers>, HelpText<"Alias for --use-dirty-headers">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "use-dirty-headers=false">, Alias<no_use_dirty_headers>, HelpText<"Alias for --no-use-dirty-headers">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "use-dirty-headers=0">, Alias<no_use_dirty_headers>, HelpText<"Alias for --no-use-dirty-headers">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +def : Flag<["--", "-"], "sync=true">, Alias<sync>, HelpText<"Alias for --sync">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "sync=false">, Alias<no_sync>, HelpText<"Alias for --no-sync">, Flags<[HelpHidden]>, Group<grp_compat_alias>; +def : Flag<["--", "-"], "sync=0">, Alias<no_sync>, HelpText<"Alias for --no-sync">, Flags<[HelpHidden]>, Group<grp_compat_alias>; + +//Check flags +def grp_check: + OptionGroup<"Check">, + HelpText<"clangd check specific options. Used for test or diagnostics">, + Flags<[HelpHidden]>; + +defm check_tidy_time : + Eq<"check-tidy-time", + "Print the overhead of checks matching this glob">, + Group<grp_check>, + Flags<[HelpHidden]>; + +defm check_file_lines: + Eq<"check-lines", + "Limits the range of tokens in -check file on which " + "various features are tested. Example --check-lines=3-7 restricts " + "testing to lines 3 to 7 (inclusive) or --check-lines=5 to restrict " + "to one line. Default is testing entire file.">, + Group<grp_check>, + Flags<[HelpHidden]>; + +defm check_locations : + B<"check-locations", + "Runs certain features (e.g. hover) at each point in the file. Somewhat slow. (enable by default)", + "Do not run certain features (e.g. hover) at each point in the file.">, + Group<grp_check>, + Flags<[HelpHidden]>; + +def check_completion : + FF<"check-completion", + "Run code-completion at each point (slow)">, + Group<grp_check>, + Flags<[HelpHidden]>; + +def check_warnings : + FF<"check-warnings", + "Print warnings as well as errors.">, + Group<grp_check>, + Flags<[HelpHidden]>; |