[llvm-branch-commits] [clang-tools-extra] [clang] [llvm] [Clangd] Migrate command line options parsing to opttable. (PR #76767)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jan 2 16:04:17 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangd

Author: Andres Villegas (avillega)

<details>
<summary>Changes</summary>

The motivation for this change is to include clangd
as part of the multicall tool. Enable clangd in the
multicall driver tool will be done a following change.


---

Patch is 62.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/76767.diff


3 Files Affected:

- (modified) clang-tools-extra/clangd/tool/CMakeLists.txt (+7) 
- (modified) clang-tools-extra/clangd/tool/ClangdMain.cpp (+372-520) 
- (added) clang-tools-extra/clangd/tool/Opts.td (+426) 


``````````diff
diff --git a/clang-tools-extra/clangd/tool/CMakeLists.txt b/clang-tools-extra/clangd/tool/CMakeLists.txt
index 6c21175d7687c3..54779463cce521 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 3b08e023236dc1..ea122d1a585c84 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 uint MallocTrimVis = (1 << 8);
+#else
+static constexpr uint 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 uint RemoteVis = (1 << 9);
+#else
+static constexpr uint 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 "
-...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/76767


More information about the llvm-branch-commits mailing list