zcov: / lib/Driver/OptTable.cpp


Files: 1 Branches Taken: 79.4% 139 / 175
Generated: 2010-02-10 01:31 Branches Executed: 79.4% 139 / 175
Line Coverage: 93.9% 170 / 181


Programs: 2 Runs 3018


       1                 : //===--- OptTable.cpp - Option Table Implementation ---------------------*-===//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : 
      10                 : #include "clang/Driver/OptTable.h"
      11                 : #include "clang/Driver/Arg.h"
      12                 : #include "clang/Driver/ArgList.h"
      13                 : #include "clang/Driver/Option.h"
      14                 : #include "llvm/Support/raw_ostream.h"
      15                 : #include <algorithm>
      16                 : #include <cassert>
      17                 : #include <map>
      18                 : using namespace clang::driver;
      19                 : using namespace clang::driver::options;
      20                 : 
      21                 : // Ordering on Info. The ordering is *almost* lexicographic, with two
      22                 : // exceptions. First, '\0' comes at the end of the alphabet instead of
      23                 : // the beginning (thus options preceed any other options which prefix
      24                 : // them). Second, for options with the same name, the less permissive
      25                 : // version should come first; a Flag option should preceed a Joined
      26                 : // option, for example.
      27                 : 
      28           688341: static int StrCmpOptionName(const char *A, const char *B) {
      29           688341:   char a = *A, b = *B;
                  3444839: branch 0 taken
                   678089: branch 1 taken
      30          4811269:   while (a == b) {
                    10252: branch 0 taken
                  3434587: branch 1 taken
      31          3444839:     if (a == '\0')
      32            10252:       return 0;
      33                 : 
      34          3434587:     a = *++A;
      35          3434587:     b = *++B;
      36                 :   }
      37                 : 
                     2913: branch 0 taken
                   675176: branch 1 taken
      38           678089:   if (a == '\0') // A is a prefix of B.
      39             2913:     return 1;
                    81068: branch 0 taken
                   594108: branch 1 taken
      40           675176:   if (b == '\0') // B is a prefix of A.
      41            81068:     return -1;
      42                 : 
      43                 :   // Otherwise lexicographic.
                   569418: branch 0 taken
                    24690: branch 1 taken
      44           594108:   return (a < b) ? -1 : 1;
      45                 : }
      46                 : 
      47                 : namespace clang {
      48                 : namespace driver {
      49           610519: static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
                        0: branch 0 not taken
                   610519: branch 1 taken
      50           610519:   if (&A == &B)
      51                0:     return false;
      52                 : 
                   609279: branch 1 taken
                     1240: branch 2 taken
      53           610519:   if (int N = StrCmpOptionName(A.Name, B.Name))
      54           609279:     return N == -1;
      55                 : 
      56                 :   // Names are the same, check that classes are in order; exactly one
      57                 :   // should be joined, and it should succeed the other.
      58                 :   assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
                        0: branch 0 not taken
                     1240: branch 1 taken
      59             1240:          "Unexpected classes for options with same name.");
      60             1240:   return B.Kind == Option::JoinedClass;
      61                 : }
      62                 : 
      63                 : // Support lower_bound between info and an option name.
      64            77822: static inline bool operator<(const OptTable::Info &I, const char *Name) {
      65            77822:   return StrCmpOptionName(I.Name, Name) == -1;
      66                 : }
      67                 : static inline bool operator<(const char *Name, const OptTable::Info &I) {
      68                 :   return StrCmpOptionName(Name, I.Name) == -1;
      69                 : }
      70                 : }
      71                 : }
      72                 : 
      73                 : //
      74                 : 
      75               18: OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
      76                 : 
      77                 : //
      78                 : 
      79             2771: OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
      80                 :   : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos),
      81                 :     Options(new Option*[NumOptionInfos]),
      82             2771:     TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0)
      83                 : {
      84                 :   // Explicitly zero initialize the error to work around a bug in array
      85                 :   // value-initialization on MinGW with gcc 4.3.5.
      86             2771:   memset(Options, 0, sizeof(*Options) * NumOptionInfos);
      87                 : 
      88                 :   // Find start of normal options.
                        0: branch 1 not taken
                        0: branch 2 not taken
                    16292: branch 4 taken
                        0: branch 5 not taken
      89            16292:   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
      90            16292:     unsigned Kind = getInfo(i + 1).Kind;
                    16292: branch 0 taken
                    16292: branch 1 taken
                     2771: branch 2 taken
                    13521: branch 3 taken
      91            16292:     if (Kind == Option::InputClass) {
                     2771: branch 0 taken
                     2771: branch 1 taken
                        0: branch 3 not taken
                     2771: branch 4 taken
      92             2771:       assert(!TheInputOption && "Cannot have multiple input options!");
      93             2771:       TheInputOption = getOption(i + 1);
                    13521: branch 0 taken
                    13521: branch 1 taken
                     2771: branch 2 taken
                    10750: branch 3 taken
      94            13521:     } else if (Kind == Option::UnknownClass) {
                     2771: branch 0 taken
                     2771: branch 1 taken
                        0: branch 3 not taken
                     2771: branch 4 taken
      95             2771:       assert(!TheUnknownOption && "Cannot have multiple input options!");
      96             2771:       TheUnknownOption = getOption(i + 1);
                    10750: branch 0 taken
                    10750: branch 1 taken
                     2771: branch 2 taken
                     7979: branch 3 taken
      97            10750:     } else if (Kind != Option::GroupClass) {
      98             2771:       FirstSearchableIndex = i;
      99             2771:       break;
     100                 :     }
     101                 :   }
                     2771: branch 0 taken
                     2771: branch 1 taken
                        0: branch 3 not taken
                     2771: branch 4 taken
     102             2771:   assert(FirstSearchableIndex != 0 && "No searchable options?");
     103                 : 
     104                 : #ifndef NDEBUG
     105                 :   // Check that everything after the first searchable option is a
     106                 :   // regular option class.
                        0: branch 1 not taken
                        0: branch 2 not taken
                   613290: branch 4 taken
                     2771: branch 5 taken
     107           616061:   for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
     108           613290:     Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
     109                 :     assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
     110                 :             Kind != Option::GroupClass) &&
                   613290: branch 0 taken
                   613290: branch 1 taken
                   613290: branch 2 taken
                   613290: branch 3 taken
                   613290: branch 4 taken
                   613290: branch 5 taken
                   613290: branch 7 taken
                        0: branch 8 not taken
                   613290: branch 9 taken
                        0: branch 10 not taken
                        0: branch 11 not taken
                   613290: branch 12 taken
     111           613290:            "Special options should be defined first!");
     112                 :   }
     113                 : 
     114                 :   // Check that options are in order.
                        0: branch 1 not taken
                        0: branch 2 not taken
                   610519: branch 4 taken
                     2771: branch 5 taken
     115           613290:   for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
                        0: branch 5 not taken
                        0: branch 6 not taken
                        0: branch 12 not taken
                   610519: branch 13 taken
     116           610519:     if (!(getInfo(i) < getInfo(i + 1))) {
     117                0:       getOption(i)->dump();
     118                0:       getOption(i + 1)->dump();
     119                0:       assert(0 && "Options are not in order!");
     120                 :     }
     121                 :   }
     122                 : #endif
     123             2771: }
     124                 : 
     125             2771: OptTable::~OptTable() {
                   626811: branch 1 taken
                     2771: branch 2 taken
                        0: branch 4 not taken
                        0: branch 5 not taken
     126           629582:   for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
                    18773: branch 0 taken
                   608038: branch 1 taken
                    18773: branch 3 taken
                    18773: branch 4 taken
     127           626811:     delete Options[i];
                     2771: branch 0 taken
                        0: branch 1 not taken
                     2771: branch 3 taken
                     2771: branch 4 taken
     128             2771:   delete[] Options;
     129             2771: }
     130                 : 
     131            18773: Option *OptTable::CreateOption(unsigned id) const {
     132            18773:   const Info &info = getInfo(id);
     133                 :   const OptionGroup *Group =
     134            18773:     cast_or_null<OptionGroup>(getOption(info.GroupID));
     135            18773:   const Option *Alias = getOption(info.AliasID);
     136                 : 
     137            18773:   Option *Opt = 0;
                     2771: branch 0 taken
                     2771: branch 1 taken
                     3056: branch 2 taken
                     6069: branch 3 taken
                      877: branch 4 taken
                     2985: branch 5 taken
                        1: branch 6 taken
                        9: branch 7 taken
                      230: branch 8 taken
                        4: branch 9 taken
                        0: branch 10 not taken
     138            18773:   switch (info.Kind) {
     139                 :   case Option::InputClass:
     140             2771:     Opt = new InputOption(id); break;
     141                 :   case Option::UnknownClass:
     142             2771:     Opt = new UnknownOption(id); break;
     143                 :   case Option::GroupClass:
     144             3056:     Opt = new OptionGroup(id, info.Name, Group); break;
     145                 :   case Option::FlagClass:
     146             6069:     Opt = new FlagOption(id, info.Name, Group, Alias); break;
     147                 :   case Option::JoinedClass:
     148              877:     Opt = new JoinedOption(id, info.Name, Group, Alias); break;
     149                 :   case Option::SeparateClass:
     150             2985:     Opt = new SeparateOption(id, info.Name, Group, Alias); break;
     151                 :   case Option::CommaJoinedClass:
     152                1:     Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
     153                 :   case Option::MultiArgClass:
     154                9:     Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
     155                 :   case Option::JoinedOrSeparateClass:
     156              230:     Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
     157                 :   case Option::JoinedAndSeparateClass:
     158                4:     Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
     159                 :   }
     160                 : 
                     3401: branch 0 taken
                    15372: branch 1 taken
     161            18773:   if (info.Flags & DriverOption)
     162             3401:     Opt->setDriverOption(true);
                        7: branch 0 taken
                    18766: branch 1 taken
     163            18773:   if (info.Flags & LinkerInput)
     164                7:     Opt->setLinkerInput(true);
                        8: branch 0 taken
                    18765: branch 1 taken
     165            18773:   if (info.Flags & NoArgumentUnused)
     166                8:     Opt->setNoArgumentUnused(true);
                       72: branch 0 taken
                    18701: branch 1 taken
     167            18773:   if (info.Flags & RenderAsInput)
     168               72:     Opt->setNoOptAsInput(true);
                        0: branch 0 not taken
                    18773: branch 1 taken
     169            18773:   if (info.Flags & RenderJoined) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     170                0:     assert(info.Kind == Option::SeparateClass && "Invalid option.");
     171                0:     Opt->setForceJoinedRender(true);
     172                 :   }
                        0: branch 0 not taken
                    18773: branch 1 taken
     173            18773:   if (info.Flags & RenderSeparate) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     174                0:     assert(info.Kind == Option::JoinedClass && "Invalid option.");
     175                0:     Opt->setForceSeparateRender(true);
     176                 :   }
                        1: branch 0 taken
                    18772: branch 1 taken
     177            18773:   if (info.Flags & Unsupported)
     178                1:     Opt->setUnsupported(true);
     179                 : 
     180            18773:   return Opt;
     181                 : }
     182                 : 
     183            12572: Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const {
     184            12572:   unsigned Prev = Index;
     185            12572:   const char *Str = Args.getArgString(Index);
     186                 : 
     187                 :   // Anything that doesn't start with '-' is an input, as is '-' itself.
                     9911: branch 0 taken
                     2661: branch 1 taken
                       17: branch 2 taken
                     9894: branch 3 taken
     188            12572:   if (Str[0] != '-' || Str[1] == '\0')
     189             2678:     return new PositionalArg(TheInputOption, Index++);
     190                 : 
     191             9894:   const Info *Start = OptionInfos + FirstSearchableIndex;
     192             9894:   const Info *End = OptionInfos + getNumOptions();
     193                 : 
     194                 :   // Search for the first next option which could be a prefix.
     195             9894:   Start = std::lower_bound(Start, End, Str);
     196                 : 
     197                 :   // Options are stored in sorted order, with '\0' at the end of the
     198                 :   // alphabet. Since the only options which can accept a string must
     199                 :   // prefix it, we iteratively search for the next option which could
     200                 :   // be a prefix.
     201                 :   //
     202                 :   // FIXME: This is searching much more than necessary, but I am
     203                 :   // blanking on the simplest way to make it fast. We can solve this
     204                 :   // problem when we move to TableGen.
                     9902: branch 0 taken
                        0: branch 1 not taken
     205             9902:   for (; Start != End; ++Start) {
     206                 :     // Scan for first option which is a proper prefix.
                    10746: branch 0 taken
                        6: branch 1 taken
     207            10752:     for (; Start != End; ++Start)
                     9896: branch 2 taken
                      850: branch 3 taken
     208            10746:       if (memcmp(Str, Start->Name, strlen(Start->Name)) == 0)
     209             9896:         break;
                        6: branch 0 taken
                     9896: branch 1 taken
     210             9902:     if (Start == End)
     211                6:       break;
     212                 : 
     213                 :     // See if this option matches.
                     9885: branch 3 taken
                       11: branch 4 taken
     214             9896:     if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index))
     215             9885:       return A;
     216                 : 
     217                 :     // Otherwise, see if this argument was missing values.
                        3: branch 0 taken
                        8: branch 1 taken
     218               11:     if (Prev != Index)
     219                3:       return 0;
     220                 :   }
     221                 : 
     222                6:   return new PositionalArg(TheUnknownOption, Index++);
     223                 : }
     224                 : 
     225                 : InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd,
     226                 :                                   unsigned &MissingArgIndex,
     227             2771:                                   unsigned &MissingArgCount) const {
     228             2771:   InputArgList *Args = new InputArgList(ArgBegin, ArgEnd);
     229                 : 
     230                 :   // FIXME: Handle '@' args (or at least error on them).
     231                 : 
     232             2771:   MissingArgIndex = MissingArgCount = 0;
     233             2771:   unsigned Index = 0, End = ArgEnd - ArgBegin;
                    12569: branch 0 taken
                     2769: branch 1 taken
     234            18109:   while (Index < End) {
     235                 :     // Ignore empty arguments (other things may still take them as arguments).
                        1: branch 1 taken
                    12568: branch 2 taken
     236            12569:     if (Args->getArgString(Index)[0] == '\0') {
     237                1:       ++Index;
     238                1:       continue;
     239                 :     }
     240                 : 
     241            12568:     unsigned Prev = Index;
     242            12568:     Arg *A = ParseOneArg(*Args, Index);
                        0: branch 0 not taken
                    12568: branch 1 taken
     243            12568:     assert(Index > Prev && "Parser failed to consume argument.");
     244                 : 
     245                 :     // Check for missing argument error.
                        2: branch 0 taken
                    12566: branch 1 taken
     246            12568:     if (!A) {
                        0: branch 0 not taken
                        2: branch 1 taken
     247                2:       assert(Index >= End && "Unexpected parser error.");
                        0: branch 0 not taken
                        2: branch 1 taken
     248                2:       assert(Index - Prev - 1 && "No missing arguments!");
     249                2:       MissingArgIndex = Prev;
     250                2:       MissingArgCount = Index - Prev - 1;
     251                2:       break;
     252                 :     }
     253                 : 
     254            12566:     Args->append(A);
     255                 :   }
     256                 : 
     257             2771:   return Args;
     258                 : }
     259                 : 
     260               78: static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
     261               78:   std::string Name = Opts.getOptionName(Id);
     262                 : 
     263                 :   // Add metavar, if used.
                        0: branch 1 not taken
                        0: branch 2 not taken
                       50: branch 3 taken
                       18: branch 4 taken
                       10: branch 5 taken
                        0: branch 6 not taken
     264               78:   switch (Opts.getOptionKind(Id)) {
     265                 :   case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
     266                0:     assert(0 && "Invalid option with help text.");
     267                 : 
     268                 :   case Option::MultiArgClass: case Option::JoinedAndSeparateClass:
     269                0:     assert(0 && "Cannot print metavar for this kind of option.");
     270                 : 
     271                 :   case Option::FlagClass:
     272               50:     break;
     273                 : 
     274                 :   case Option::SeparateClass: case Option::JoinedOrSeparateClass:
     275               18:     Name += ' ';
     276                 :     // FALLTHROUGH
     277                 :   case Option::JoinedClass: case Option::CommaJoinedClass:
                       26: branch 1 taken
                        2: branch 2 taken
     278               28:     if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
     279               26:       Name += MetaVarName;
     280                 :     else
     281                2:       Name += "<value>";
     282                 :     break;
     283                 :   }
     284                 : 
     285                 :   return Name;
     286                 : }
     287                 : 
     288                 : static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title,
     289                 :                                 std::vector<std::pair<std::string,
     290                4:                                 const char*> > &OptionHelp) {
     291                4:   OS << Title << ":\n";
     292                 : 
     293                 :   // Find the maximum option length.
     294                4:   unsigned OptionFieldWidth = 0;
                       78: branch 1 taken
                        4: branch 2 taken
     295               82:   for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
     296                 :     // Skip titles.
                        0: branch 1 not taken
                       78: branch 2 taken
     297               78:     if (!OptionHelp[i].second)
     298                0:       continue;
     299                 : 
     300                 :     // Limit the amount of padding we are willing to give up for alignment.
     301               78:     unsigned Length = OptionHelp[i].first.size();
                       72: branch 0 taken
                        6: branch 1 taken
     302               78:     if (Length <= 23)
     303               72:       OptionFieldWidth = std::max(OptionFieldWidth, Length);
     304                 :   }
     305                 : 
     306                4:   const unsigned InitialPad = 2;
                       78: branch 1 taken
                        4: branch 2 taken
     307               82:   for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
     308               78:     const std::string &Option = OptionHelp[i].first;
     309               78:     int Pad = OptionFieldWidth - int(Option.size());
     310               78:     OS.indent(InitialPad) << Option;
     311                 : 
     312                 :     // Break on long option names.
                        6: branch 0 taken
                       72: branch 1 taken
     313               78:     if (Pad < 0) {
     314                6:       OS << "\n";
     315                6:       Pad = OptionFieldWidth + InitialPad;
     316                 :     }
     317               78:     OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
     318                 :   }
     319                4: }
     320                 : 
     321               82: static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
     322               82:   unsigned GroupID = Opts.getOptionGroupID(Id);
     323                 : 
     324                 :   // If not in a group, return the default help group.
                       63: branch 0 taken
                       19: branch 1 taken
     325               82:   if (!GroupID)
     326               63:     return "OPTIONS";
     327                 : 
     328                 :   // Abuse the help text of the option groups to store the "help group"
     329                 :   // name.
     330                 :   //
     331                 :   // FIXME: Split out option groups.
                       15: branch 2 taken
                        4: branch 3 taken
     332               19:   if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
     333               15:     return GroupHelp;
     334                 : 
     335                 :   // Otherwise keep looking.
     336                4:   return getOptionHelpGroup(Opts, GroupID);
     337                 : }
     338                 : 
     339                 : void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name,
     340                2:                          const char *Title, bool ShowHidden) const {
     341                2:   OS << "OVERVIEW: " << Title << "\n";
     342                2:   OS << '\n';
     343                2:   OS << "USAGE: " << Name << " [options] <inputs>\n";
     344                2:   OS << '\n';
     345                 : 
     346                 :   // Render help text into a map of group-name to a list of (option, help)
     347                 :   // pairs.
     348                 :   typedef std::map<std::string,
     349                 :                  std::vector<std::pair<std::string, const char*> > > helpmap_ty;
     350                2:   helpmap_ty GroupedOptionHelp;
     351                 : 
                     1128: branch 1 taken
                        2: branch 2 taken
     352             1130:   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
     353             1128:     unsigned Id = i + 1;
     354                 : 
     355                 :     // FIXME: Split out option groups.
                       44: branch 2 taken
                     1084: branch 3 taken
     356             1128:     if (getOptionKind(Id) == Option::GroupClass)
     357               44:       continue;
     358                 : 
                      542: branch 0 taken
                      542: branch 1 taken
                       17: branch 4 taken
                      525: branch 5 taken
                       17: branch 6 taken
                     1067: branch 7 taken
     359             1084:     if (!ShowHidden && isOptionHelpHidden(Id))
     360               17:       continue;
     361                 : 
                       78: branch 2 taken
                      989: branch 3 taken
     362             1067:     if (const char *Text = getOptionHelpText(Id)) {
     363               78:       const char *HelpGroup = getOptionHelpGroup(*this, Id);
     364               78:       const std::string &OptName = getOptionHelpName(*this, Id);
     365               78:       GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text));
     366                 :     }
     367                 :   }
     368                 : 
                        4: branch 3 taken
                        2: branch 4 taken
     369                8:   for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
     370                2:          ie = GroupedOptionHelp.end(); it != ie; ++it) {
                        2: branch 2 taken
                        2: branch 3 taken
     371                4:     if (it != GroupedOptionHelp .begin())
     372                2:       OS << "\n";
     373                4:     PrintHelpOptionList(OS, it->first, it->second);
     374                 :   }
     375                 : 
     376                2:   OS.flush();
     377                2: }

Generated: 2010-02-10 01:31 by zcov