diff options
| -rw-r--r-- | llvm/include/llvm/Support/CommandLine.h | 8 | ||||
| -rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 19 | ||||
| -rw-r--r-- | llvm/unittests/Support/CommandLineTest.cpp | 74 | 
3 files changed, 94 insertions, 7 deletions
| diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index 1280775b4fa..a78020f010f 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -155,6 +155,9 @@ enum OptionHidden {   // Control whether -help shows this option  // enabled, and used, the value for the flag comes from the suffix of the  // argument.  // +// AlwaysPrefix - Only allow the behavior enabled by the Prefix flag and reject +// the Option=Value form. +//  // Grouping - With this option enabled, multiple letter options are allowed to  // bunch together with only a single hyphen for the whole group.  This allows  // emulation of the behavior that ls uses for example: ls -la === ls -l -a @@ -164,7 +167,8 @@ enum FormattingFlags {    NormalFormatting = 0x00, // Nothing special    Positional = 0x01,       // Is a positional argument, no '-' required    Prefix = 0x02,           // Can this option directly prefix its value? -  Grouping = 0x03          // Can this option group with other options? +  AlwaysPrefix = 0x03,     // Can this option only directly prefix its value? +  Grouping = 0x04          // Can this option group with other options?  };  enum MiscFlags {             // Miscellaneous flags to adjust argument @@ -264,7 +268,7 @@ class Option {    // detail representing the non-value    unsigned Value : 2;    unsigned HiddenFlag : 2; // enum OptionHidden -  unsigned Formatting : 2; // enum FormattingFlags +  unsigned Formatting : 3; // enum FormattingFlags    unsigned Misc : 3;    unsigned Position = 0;       // Position of last occurrence of the option    unsigned AdditionalVals = 0; // Greater than 0 for multi-valued option. diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 52f1c0e007b..b0c92b7c72c 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -425,12 +425,17 @@ Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg,      return I != Sub.OptionsMap.end() ? I->second : nullptr;    } -  // If the argument before the = is a valid option name, we match.  If not, -  // return Arg unmolested. +  // If the argument before the = is a valid option name and the option allows +  // non-prefix form (ie is not AlwaysPrefix), we match.  If not, signal match +  // failure by returning nullptr.    auto I = Sub.OptionsMap.find(Arg.substr(0, EqualPos));    if (I == Sub.OptionsMap.end())      return nullptr; +  auto O = I->second; +  if (O->getFormattingFlag() == cl::AlwaysPrefix) +    return nullptr; +    Value = Arg.substr(EqualPos + 1);    Arg = Arg.substr(0, EqualPos);    return I->second; @@ -538,7 +543,9 @@ static inline bool ProvideOption(Option *Handler, StringRef ArgName,    switch (Handler->getValueExpectedFlag()) {    case ValueRequired:      if (!Value.data()) { // No value specified? -      if (i + 1 >= argc) +      // If no other argument or the option only supports prefix form, we +      // cannot look at the next argument. +      if (i + 1 >= argc || Handler->getFormattingFlag() == cl::AlwaysPrefix)          return Handler->error("requires a value!");        // Steal the next argument, like for '-o filename'        assert(argv && "null check"); @@ -596,7 +603,8 @@ static inline bool isGrouping(const Option *O) {    return O->getFormattingFlag() == cl::Grouping;  }  static inline bool isPrefixedOrGrouping(const Option *O) { -  return isGrouping(O) || O->getFormattingFlag() == cl::Prefix; +  return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || +         O->getFormattingFlag() == cl::AlwaysPrefix;  }  // getOptionPred - Check to see if there are any options that satisfy the @@ -646,7 +654,8 @@ HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value,    // If the option is a prefixed option, then the value is simply the    // rest of the name...  so fall through to later processing, by    // setting up the argument name flags and value fields. -  if (PGOpt->getFormattingFlag() == cl::Prefix) { +  if (PGOpt->getFormattingFlag() == cl::Prefix || +      PGOpt->getFormattingFlag() == cl::AlwaysPrefix) {      Value = Arg.substr(Length);      Arg = Arg.substr(0, Length);      assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt); diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 150563b5b0b..f9841f580b1 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -1054,4 +1054,78 @@ TEST_F(GetOptionWidthTest,              ExpectedStrSize);  } +TEST(CommandLineTest, PrefixOptions) { +  cl::ResetCommandLineParser(); + +  StackOption<std::string, cl::list<std::string>> IncludeDirs( +      "I", cl::Prefix, cl::desc("Declare an include directory")); + +  // Test non-prefixed variant works with cl::Prefix options. +  EXPECT_TRUE(IncludeDirs.empty()); +  const char *args[] = {"prog", "-I=/usr/include"}; +  EXPECT_TRUE( +      cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); +  EXPECT_TRUE(IncludeDirs.size() == 1); +  EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); + +  IncludeDirs.erase(IncludeDirs.begin()); +  cl::ResetAllOptionOccurrences(); + +  // Test non-prefixed variant works with cl::Prefix options when value is +  // passed in following argument. +  EXPECT_TRUE(IncludeDirs.empty()); +  const char *args2[] = {"prog", "-I", "/usr/include"}; +  EXPECT_TRUE( +      cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); +  EXPECT_TRUE(IncludeDirs.size() == 1); +  EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); + +  IncludeDirs.erase(IncludeDirs.begin()); +  cl::ResetAllOptionOccurrences(); + +  // Test prefixed variant works with cl::Prefix options. +  EXPECT_TRUE(IncludeDirs.empty()); +  const char *args3[] = {"prog", "-I/usr/include"}; +  EXPECT_TRUE( +      cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls())); +  EXPECT_TRUE(IncludeDirs.size() == 1); +  EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0); + +  StackOption<std::string, cl::list<std::string>> MacroDefs( +      "D", cl::AlwaysPrefix, cl::desc("Define a macro"), +      cl::value_desc("MACRO[=VALUE]")); + +  cl::ResetAllOptionOccurrences(); + +  // Test non-prefixed variant does not work with cl::AlwaysPrefix options: +  // equal sign is part of the value. +  EXPECT_TRUE(MacroDefs.empty()); +  const char *args4[] = {"prog", "-D=HAVE_FOO"}; +  EXPECT_TRUE( +      cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls())); +  EXPECT_TRUE(MacroDefs.size() == 1); +  EXPECT_TRUE(MacroDefs.front().compare("=HAVE_FOO") == 0); + +  MacroDefs.erase(MacroDefs.begin()); +  cl::ResetAllOptionOccurrences(); + +  // Test non-prefixed variant does not allow value to be passed in following +  // argument with cl::AlwaysPrefix options. +  EXPECT_TRUE(MacroDefs.empty()); +  const char *args5[] = {"prog", "-D", "HAVE_FOO"}; +  EXPECT_FALSE( +      cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls())); +  EXPECT_TRUE(MacroDefs.empty()); + +  cl::ResetAllOptionOccurrences(); + +  // Test prefixed variant works with cl::AlwaysPrefix options. +  EXPECT_TRUE(MacroDefs.empty()); +  const char *args6[] = {"prog", "-DHAVE_FOO"}; +  EXPECT_TRUE( +      cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls())); +  EXPECT_TRUE(MacroDefs.size() == 1); +  EXPECT_TRUE(MacroDefs.front().compare("HAVE_FOO") == 0); +} +  }  // anonymous namespace | 

