teemperor created this revision.
teemperor added a reviewer: JDevlieghere.
Herald added subscribers: lldb-commits, abidh.
Herald added a project: LLDB.
teemperor added a comment.

For the sake of completeness, that's how Clang would warn about unimplemented 
options:

  llvm-project/lldb/source/Commands/CommandObjectSettings.cpp:102:15: warning: 
enumeration value 'Global' not handled in switch [-Wswitch]
        switch (*opt) {
                ^
  llvm-project/lldb/source/Commands/CommandObjectSettings.cpp:102:15: note: add 
missing switch cases
        switch (*opt) {
                ^


Currently in LLDB we handle options like this:

  switch(short_option) {
  case 'g': m_force = true; break;
  case 'f': m_global = true; supportGlobal(); break;
  default:
    error.SetErrorStringWithFormat("unrecognized options '%c'",
                                         short_option);
    break;

This format has a two problems:

1. If we don't handle an option in this switch statement (because of a typo, a 
changed short-option

name, or because someone just forgot to implement it), we only find out when we 
have a test or user
that notices we get an error when using this option. There is no compile-time 
verification of this.

2. It's not very easy to read unless you know all the short options for all 
commands.

This patch makes our tablegen emit an enum that represents the options, which 
changes the code above to this (using SettingsSet as an example):

  auto opt = toSettingsSetEnum(short_option, error);
  if (!opt)
    return error;
  
  switch (opt) {
  case SettingsSet::Global: m_force = true; break;
  case SettingsSet::Force: m_global = true; supportGlobal(); break;
  // No default with error handling, already handled in toSettingsSetEnum.
  // If you don't implement an option, this will trigger a compiler warning for 
unhandled enum value.
  }



NOTE: This is just a dummy patch to get some feedback if people are for some 
reason opposed to this change
(which would save me from converting all our switch-cases to the new format). I 
only changed the code for
`settings set` to demonstrate the change.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D65386

Files:
  lldb/source/Commands/CommandObjectSettings.cpp
  lldb/utils/TableGen/LLDBOptionDefEmitter.cpp

Index: lldb/utils/TableGen/LLDBOptionDefEmitter.cpp
===================================================================
--- lldb/utils/TableGen/LLDBOptionDefEmitter.cpp
+++ lldb/utils/TableGen/LLDBOptionDefEmitter.cpp
@@ -160,6 +160,44 @@
   OS << "},\n";
 }
 
+static std::string Capitalize(llvm::StringRef s) {
+  return s.substr(0, 1).upper() + s.substr(1).str();
+}
+static std::string ToCamelCase(llvm::StringRef In) {
+  llvm::SmallVector<StringRef, 4> Parts;
+  llvm::SplitString(In, Parts, "-_ ");
+  std::string Result;
+  for (llvm::StringRef S : Parts)
+    Result.append(Capitalize(S));
+  return Result;
+}
+
+static void emitEnumDeclaration(llvm::StringRef EnumName,
+                                const std::vector<CommandOption> &Options,
+                                raw_ostream &OS) {
+  OS << "namespace { enum class " << EnumName << " {\n";
+  for (const CommandOption &CO : Options)
+    OS << "  " << ToCamelCase(CO.FullName) << ",\n";
+  OS << "}; }\n";
+}
+
+static void emitEnumSwitch(llvm::StringRef EnumName,
+                           const std::vector<CommandOption> &Options,
+                           raw_ostream &OS) {
+  OS << "static llvm::Optional<" << EnumName << "> to" << EnumName
+     << "(char c, Status error) {\n";
+  OS << "  switch(c) {";
+  for (const CommandOption &CO : Options)
+    OS << "    case '" << CO.ShortName << "': return " << EnumName
+       << "::" << ToCamelCase(CO.FullName) << ";\n";
+  OS << R"cpp(
+    default:
+      error.SetErrorStringWithFormat("unrecognized option '%c'", c);
+      return {};
+)cpp";
+  OS << "  }\n}\n";
+}
+
 /// Emits all option initializers to the raw_ostream.
 static void emitOptions(std::string Command, std::vector<Record *> Records,
                         raw_ostream &OS) {
@@ -169,6 +207,9 @@
 
   std::string ID = Command;
   std::replace(ID.begin(), ID.end(), ' ', '_');
+
+  std::string CamelCaseID = ToCamelCase(Command);
+
   // Generate the macro that the user needs to define before including the
   // *.inc file.
   std::string NeededMacro = "LLDB_OPTIONS_" + ID;
@@ -180,8 +221,13 @@
   OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n";
   for (CommandOption &CO : Options)
     emitOption(CO, OS);
-  // We undefine the macro for the user like Clang's include files are doing it.
   OS << "};\n";
+
+  std::string Enum = "OptionEnum" + CamelCaseID;
+  emitEnumDeclaration(Enum, Options, OS);
+  emitEnumSwitch(Enum, Options, OS);
+
+  // We undefine the macro for the user like Clang's include files are doing it.
   OS << "#undef " << NeededMacro << "\n";
   OS << "#endif // " << Command << " command\n\n";
 }
Index: lldb/source/Commands/CommandObjectSettings.cpp
===================================================================
--- lldb/source/Commands/CommandObjectSettings.cpp
+++ lldb/source/Commands/CommandObjectSettings.cpp
@@ -94,19 +94,18 @@
     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
                           ExecutionContext *execution_context) override {
       Status error;
-      const int short_option = m_getopt_table[option_idx].val;
 
-      switch (short_option) {
-      case 'f':
+      auto opt = toOptionEnumSettingsSet(m_getopt_table[option_idx].val, error);
+      if (!opt)
+        return error;
+
+      switch (*opt) {
+      case OptionEnumSettingsSet::Force:
         m_force = true;
         break;
-      case 'g':
+      case OptionEnumSettingsSet::Global:
         m_global = true;
         break;
-      default:
-        error.SetErrorStringWithFormat("unrecognized options '%c'",
-                                       short_option);
-        break;
       }
 
       return error;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to