aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/tool/CMakeLists.txt7
-rw-r--r--clang-tools-extra/clangd/tool/ClangdMain.cpp891
-rw-r--r--clang-tools-extra/clangd/tool/Opts.td426
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]>;