[Options] Add prefixes to options.

Each option has a set of prefixes. When matching an argument such as
-funroll-loops. First the leading - is removed as it is a prefix. Then
a lower_bound search for "funroll-loops" is done against the option table by
option name. From there each option prefix + option name combination is tested
against the argument.

This allows us to support Microsoft style options where both / and - are valid
prefixes. It also simplifies the cases we already have where options come in
both - and -- forms. Almost every option for gnu-ld happens to have this form.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166444 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index b156d7c..2431051 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Driver/Arg.h"
+#include "clang/Basic/LLVM.h"
 #include "clang/Driver/ArgList.h"
 #include "clang/Driver/Option.h"
 #include "llvm/ADT/SmallString.h"
@@ -15,22 +16,23 @@
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang::driver;
+using clang::StringRef;
 
-Arg::Arg(const Option _Opt, unsigned _Index, const Arg *_BaseArg)
-  : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg)
+  : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
     Claimed(false), OwnsValues(false) {
 }
 
-Arg::Arg(const Option _Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
          const char *Value0, const Arg *_BaseArg)
-  : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+  : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
     Claimed(false), OwnsValues(false) {
   Values.push_back(Value0);
 }
 
-Arg::Arg(const Option _Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
          const char *Value0, const char *Value1, const Arg *_BaseArg)
-  : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+  : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
     Claimed(false), OwnsValues(false) {
   Values.push_back(Value0);
   Values.push_back(Value1);
@@ -96,7 +98,7 @@
   case Option::RenderCommaJoinedStyle: {
     SmallString<256> Res;
     llvm::raw_svector_ostream OS(Res);
-    OS << getOption().getName();
+    OS << getSpelling();
     for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
       if (i) OS << ',';
       OS << getValue(Args, i);
@@ -107,13 +109,13 @@
 
  case Option::RenderJoinedStyle:
     Output.push_back(Args.GetOrMakeJoinedArgString(
-                       getIndex(), getOption().getName(), getValue(Args, 0)));
+                       getIndex(), getSpelling(), getValue(Args, 0)));
     for (unsigned i = 1, e = getNumValues(); i != e; ++i)
       Output.push_back(getValue(Args, i));
     break;
 
   case Option::RenderSeparateStyle:
-    Output.push_back(getOption().getName().data());
+    Output.push_back(Args.MakeArgString(getSpelling()));
     for (unsigned i = 0, e = getNumValues(); i != e; ++i)
       Output.push_back(getValue(Args, i));
     break;
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 3b824f7..28d6b1e 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -363,7 +363,9 @@
 }
 
 Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const {
-  Arg *A = new Arg(Opt, BaseArgs.MakeIndex(Opt.getName()), BaseArg);
+  Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+                                               Twine(Opt.getName())),
+                   BaseArgs.MakeIndex(Opt.getName()), BaseArg);
   SynthesizedArgs.push_back(A);
   return A;
 }
@@ -371,7 +373,9 @@
 Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
                                        StringRef Value) const {
   unsigned Index = BaseArgs.MakeIndex(Value);
-  Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg);
+  Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+                                               Twine(Opt.getName())),
+                   Index, BaseArgs.getArgString(Index), BaseArg);
   SynthesizedArgs.push_back(A);
   return A;
 }
@@ -379,7 +383,9 @@
 Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
                                      StringRef Value) const {
   unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value);
-  Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg);
+  Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+                                               Twine(Opt.getName())),
+                   Index, BaseArgs.getArgString(Index + 1), BaseArg);
   SynthesizedArgs.push_back(A);
   return A;
 }
@@ -387,7 +393,8 @@
 Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt,
                                    StringRef Value) const {
   unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str());
-  Arg *A = new Arg(Opt, Index,
+  Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+                                               Twine(Opt.getName())), Index,
                    BaseArgs.getArgString(Index) + Opt.getName().size(),
                    BaseArg);
   SynthesizedArgs.push_back(A);
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index cc7c7a4..4f89b73 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -15,11 +15,19 @@
 using namespace clang::driver::options;
 using namespace clang::driver::cc1asoptions;
 
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+               HELPTEXT, METAVAR)
+#include "clang/Driver/CC1AsOptions.inc"
+#undef OPTION
+#undef PREFIX
+
 static const OptTable::Info CC1AsInfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
                HELPTEXT, METAVAR)   \
-  { NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, FLAGS, \
-    OPT_##GROUP, OPT_##ALIAS },
+  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+    FLAGS, OPT_##GROUP, OPT_##ALIAS },
 #include "clang/Driver/CC1AsOptions.inc"
 };
 
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 59cebf5..31492a7 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -608,7 +608,7 @@
        it != ie; ++it, ++i) {
     Arg *A = *it;
     llvm::errs() << "Option " << i << " - "
-                 << "Name: \"" << A->getOption().getName() << "\", "
+                 << "Name: \"" << A->getOption().getPrefixedName() << "\", "
                  << "Values: {";
     for (unsigned j = 0; j < A->getNumValues(); ++j) {
       if (j)
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index f9d36cf..3925b8a 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -14,11 +14,19 @@
 using namespace clang::driver;
 using namespace clang::driver::options;
 
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+               HELPTEXT, METAVAR)
+#include "clang/Driver/Options.inc"
+#undef OPTION
+#undef PREFIX
+
 static const OptTable::Info InfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
                HELPTEXT, METAVAR)   \
-  { NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, FLAGS, \
-    OPT_##GROUP, OPT_##ALIAS },
+  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+    FLAGS, OPT_##GROUP, OPT_##ALIAS },
 #include "clang/Driver/Options.inc"
 };
 
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index a1c5ecd..db59298 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -55,6 +55,13 @@
   if (int N = StrCmpOptionName(A.Name, B.Name))
     return N == -1;
 
+  for (const char * const *APre = A.Prefixes,
+                  * const *BPre = B.Prefixes;
+                          *APre != 0 && *BPre != 0; ++APre, ++BPre) {
+    if (int N = StrCmpOptionName(*APre, *BPre))
+      return N == -1;
+  }
+
   // Names are the same, check that classes are in order; exactly one
   // should be joined, and it should succeed the other.
   assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
@@ -123,6 +130,26 @@
     }
   }
 #endif
+
+  // Build prefixes.
+  for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
+    if (const char *const *P = getInfo(i).Prefixes) {
+      for (; *P != 0; ++P) {
+        PrefixesUnion.insert(*P);
+      }
+    }
+  }
+
+  // Build prefix chars.
+  for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(),
+                                         E = PrefixesUnion.end(); I != E; ++I) {
+    StringRef Prefix = I->getKey();
+    for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end();
+                                   C != CE; ++C)
+      if (std::find(PrefixChars.begin(), PrefixChars.end(), *C)
+            == PrefixChars.end())
+        PrefixChars.push_back(*C);
+  }
 }
 
 OptTable::~OptTable() {
@@ -140,19 +167,41 @@
   return getInfo(id).Flags & options::HelpHidden;
 }
 
+static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) {
+  if (Arg == "-")
+    return true;
+  for (llvm::StringSet<>::const_iterator I = Prefixes.begin(),
+                                         E = Prefixes.end(); I != E; ++I)
+    if (Arg.startswith(I->getKey()))
+      return false;
+  return true;
+}
+
+/// \returns Matched size. 0 means no match.
+static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
+  for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
+    StringRef Prefix(*Pre);
+    if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
+      return Prefix.size() + StringRef(I->Name).size();
+  }
+  return 0;
+}
+
 Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
   unsigned Prev = Index;
   const char *Str = Args.getArgString(Index);
 
-  // Anything that doesn't start with '-' is an input, as is '-' itself.
-  if (Str[0] != '-' || Str[1] == '\0')
-    return new Arg(getOption(TheInputOptionID), Index++, Str);
+  // Anything that doesn't start with PrefixesUnion is an input, as is '-'
+  // itself.
+  if (isInput(PrefixesUnion, Str))
+    return new Arg(getOption(TheInputOptionID), Str, Index++, Str);
 
   const Info *Start = OptionInfos + FirstSearchableIndex;
   const Info *End = OptionInfos + getNumOptions();
+  StringRef Name = StringRef(Str).ltrim(PrefixChars);
 
   // Search for the first next option which could be a prefix.
-  Start = std::lower_bound(Start, End, Str);
+  Start = std::lower_bound(Start, End, Name.data());
 
   // Options are stored in sorted order, with '\0' at the end of the
   // alphabet. Since the only options which can accept a string must
@@ -162,17 +211,17 @@
   // FIXME: This is searching much more than necessary, but I am
   // blanking on the simplest way to make it fast. We can solve this
   // problem when we move to TableGen.
-  StringRef StrRef(Str);
   for (; Start != End; ++Start) {
+    unsigned ArgSize = 0;
     // Scan for first option which is a proper prefix.
     for (; Start != End; ++Start)
-      if (StrRef.startswith(Start->Name))
+      if ((ArgSize = matchOption(Start, Str)))
         break;
     if (Start == End)
       break;
 
     // See if this option matches.
-    if (Arg *A = getOption(Start - OptionInfos + 1).accept(Args, Index))
+    if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
       return A;
 
     // Otherwise, see if this argument was missing values.
@@ -180,7 +229,7 @@
       return 0;
   }
 
-  return new Arg(getOption(TheUnknownOptionID), Index++, Str);
+  return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
 }
 
 InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
@@ -220,10 +269,11 @@
 }
 
 static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
-  std::string Name = Opts.getOptionName(Id);
+  const Option O = Opts.getOption(Id);
+  std::string Name = O.getPrefixedName();
 
   // Add metavar, if used.
-  switch (Opts.getOptionKind(Id)) {
+  switch (O.getKind()) {
   case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
     llvm_unreachable("Invalid option with help text.");
 
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index e9440c5..a22cb15 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -48,6 +48,12 @@
 #undef P
   }
 
+  llvm::errs() << " Prefixes:[";
+  for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
+    llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
+  }
+  llvm::errs() << ']';
+
   llvm::errs() << " Name:\"" << getName() << '"';
 
   const Option Group = getGroup();
@@ -84,21 +90,24 @@
   return false;
 }
 
-Arg *Option::accept(const ArgList &Args, unsigned &Index) const {
+Arg *Option::accept(const ArgList &Args,
+                    unsigned &Index,
+                    unsigned ArgSize) const {
+  StringRef Spelling(Args.getArgString(Index), ArgSize);
   switch (getKind()) {
   case FlagClass:
-    if (getName().size() != strlen(Args.getArgString(Index)))
+    if (ArgSize != strlen(Args.getArgString(Index)))
       return 0;
 
-    return new Arg(getUnaliasedOption(), Index++);
+    return new Arg(getUnaliasedOption(), Spelling, Index++);
   case JoinedClass: {
-    const char *Value = Args.getArgString(Index) + getName().size();
-    return new Arg(getUnaliasedOption(), Index++, Value);
+    const char *Value = Args.getArgString(Index) + ArgSize;
+    return new Arg(getUnaliasedOption(), Spelling, Index++, Value);
   }
   case CommaJoinedClass: {
     // Always matches.
-    const char *Str = Args.getArgString(Index) + getName().size();
-    Arg *A = new Arg(getUnaliasedOption(), Index++);
+    const char *Str = Args.getArgString(Index) + ArgSize;
+    Arg *A = new Arg(getUnaliasedOption(), Spelling, Index++);
 
     // Parse out the comma separated values.
     const char *Prev = Str;
@@ -126,26 +135,26 @@
   case SeparateClass:
     // Matches iff this is an exact match.
     // FIXME: Avoid strlen.
-    if (getName().size() != strlen(Args.getArgString(Index)))
+    if (ArgSize != strlen(Args.getArgString(Index)))
       return 0;
 
     Index += 2;
     if (Index > Args.getNumInputArgStrings())
       return 0;
 
-    return new Arg(getUnaliasedOption(),
+    return new Arg(getUnaliasedOption(), Spelling,
                    Index - 2, Args.getArgString(Index - 1));
   case MultiArgClass: {
     // Matches iff this is an exact match.
     // FIXME: Avoid strlen.
-    if (getName().size() != strlen(Args.getArgString(Index)))
+    if (ArgSize != strlen(Args.getArgString(Index)))
       return 0;
 
     Index += 1 + getNumArgs();
     if (Index > Args.getNumInputArgStrings())
       return 0;
 
-    Arg *A = new Arg(getUnaliasedOption(), Index - 1 - getNumArgs(),
+    Arg *A = new Arg(getUnaliasedOption(), Spelling, Index - 1 - getNumArgs(),
                       Args.getArgString(Index - getNumArgs()));
     for (unsigned i = 1; i != getNumArgs(); ++i)
       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
@@ -154,9 +163,9 @@
   case JoinedOrSeparateClass: {
     // If this is not an exact match, it is a joined arg.
     // FIXME: Avoid strlen.
-    if (getName().size() != strlen(Args.getArgString(Index))) {
-      const char *Value = Args.getArgString(Index) + getName().size();
-      return new Arg(*this, Index++, Value);
+    if (ArgSize != strlen(Args.getArgString(Index))) {
+      const char *Value = Args.getArgString(Index) + ArgSize;
+      return new Arg(*this, Spelling, Index++, Value);
     }
 
     // Otherwise it must be separate.
@@ -164,7 +173,7 @@
     if (Index > Args.getNumInputArgStrings())
       return 0;
 
-    return new Arg(getUnaliasedOption(),
+    return new Arg(getUnaliasedOption(), Spelling,
                    Index - 2, Args.getArgString(Index - 1));
   }
   case JoinedAndSeparateClass:
@@ -173,9 +182,9 @@
     if (Index > Args.getNumInputArgStrings())
       return 0;
 
-    return new Arg(getUnaliasedOption(), Index - 2,
-                   Args.getArgString(Index-2)+getName().size(),
-                   Args.getArgString(Index-1));
+    return new Arg(getUnaliasedOption(), Spelling, Index - 2,
+                   Args.getArgString(Index - 2) + ArgSize,
+                   Args.getArgString(Index - 1));
   default:
     llvm_unreachable("Invalid option kind!");
   }
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 7848b48..54ec0cb 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1175,8 +1175,8 @@
     (*it)->claim();
 
     // Skip over "-m".
-    assert(Name.startswith("-m") && "Invalid feature name.");
-    Name = Name.substr(2);
+    assert(Name.startswith("m") && "Invalid feature name.");
+    Name = Name.substr(1);
 
     bool IsNegative = Name.startswith("no-");
     if (IsNegative)
@@ -2283,7 +2283,7 @@
       CmdArgs.push_back("-fbounds-checking=1");
   }
 
-  if (Args.hasArg(options::OPT__relocatable_pch))
+  if (Args.hasArg(options::OPT_relocatable_pch))
     CmdArgs.push_back("-relocatable-pch");
 
   if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 4f0cfa8..1de547d 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1001,10 +1001,10 @@
   for (arg_iterator I = Args.filtered_begin(OPT_W_Group),
          E = Args.filtered_end(); I != E; ++I) {
     Arg *A = *I;
-    // If the argument is a pure flag, add its name (minus the "-W" at the beginning)
+    // If the argument is a pure flag, add its name (minus the "W" at the beginning)
     // to the warning list. Else, add its value (for the OPT_W case).
     if (A->getOption().getKind() == Option::FlagClass) {
-      Warnings.push_back(A->getOption().getName().substr(2));
+      Warnings.push_back(A->getOption().getName().substr(1));
     } else {
       for (unsigned Idx = 0, End = A->getNumValues();
            Idx < End; ++Idx) {