OptTable.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. //===- OptTable.cpp - Option Table Implementation -------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/Option/OptTable.h"
  9. #include "llvm/ADT/STLExtras.h"
  10. #include "llvm/ADT/StringRef.h"
  11. #include "llvm/Option/Arg.h"
  12. #include "llvm/Option/ArgList.h"
  13. #include "llvm/Option/OptSpecifier.h"
  14. #include "llvm/Option/Option.h"
  15. #include "llvm/Support/CommandLine.h" // for expandResponseFiles
  16. #include "llvm/Support/Compiler.h"
  17. #include "llvm/Support/ErrorHandling.h"
  18. #include "llvm/Support/raw_ostream.h"
  19. #include <algorithm>
  20. #include <cassert>
  21. #include <cctype>
  22. #include <cstring>
  23. #include <map>
  24. #include <set>
  25. #include <string>
  26. #include <utility>
  27. #include <vector>
  28. using namespace llvm;
  29. using namespace llvm::opt;
  30. namespace llvm {
  31. namespace opt {
  32. // Ordering on Info. The ordering is *almost* case-insensitive lexicographic,
  33. // with an exception. '\0' comes at the end of the alphabet instead of the
  34. // beginning (thus options precede any other options which prefix them).
  35. static int StrCmpOptionNameIgnoreCase(StringRef A, StringRef B) {
  36. size_t MinSize = std::min(A.size(), B.size());
  37. if (int Res = A.substr(0, MinSize).compare_insensitive(B.substr(0, MinSize)))
  38. return Res;
  39. if (A.size() == B.size())
  40. return 0;
  41. return (A.size() == MinSize) ? 1 /* A is a prefix of B. */
  42. : -1 /* B is a prefix of A */;
  43. }
  44. #ifndef NDEBUG
  45. static int StrCmpOptionName(StringRef A, StringRef B) {
  46. if (int N = StrCmpOptionNameIgnoreCase(A, B))
  47. return N;
  48. return A.compare(B);
  49. }
  50. static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
  51. if (&A == &B)
  52. return false;
  53. if (int N = StrCmpOptionName(A.Name, B.Name))
  54. return N < 0;
  55. for (size_t I = 0, K = std::min(A.Prefixes.size(), B.Prefixes.size()); I != K;
  56. ++I)
  57. if (int N = StrCmpOptionName(A.Prefixes[I], B.Prefixes[I]))
  58. return N < 0;
  59. // Names are the same, check that classes are in order; exactly one
  60. // should be joined, and it should succeed the other.
  61. assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
  62. "Unexpected classes for options with same name.");
  63. return B.Kind == Option::JoinedClass;
  64. }
  65. #endif
  66. // Support lower_bound between info and an option name.
  67. static inline bool operator<(const OptTable::Info &I, StringRef Name) {
  68. return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0;
  69. }
  70. } // end namespace opt
  71. } // end namespace llvm
  72. OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
  73. OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
  74. : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) {
  75. // Explicitly zero initialize the error to work around a bug in array
  76. // value-initialization on MinGW with gcc 4.3.5.
  77. // Find start of normal options.
  78. for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
  79. unsigned Kind = getInfo(i + 1).Kind;
  80. if (Kind == Option::InputClass) {
  81. assert(!InputOptionID && "Cannot have multiple input options!");
  82. InputOptionID = getInfo(i + 1).ID;
  83. } else if (Kind == Option::UnknownClass) {
  84. assert(!UnknownOptionID && "Cannot have multiple unknown options!");
  85. UnknownOptionID = getInfo(i + 1).ID;
  86. } else if (Kind != Option::GroupClass) {
  87. FirstSearchableIndex = i;
  88. break;
  89. }
  90. }
  91. assert(FirstSearchableIndex != 0 && "No searchable options?");
  92. #ifndef NDEBUG
  93. // Check that everything after the first searchable option is a
  94. // regular option class.
  95. for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
  96. Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
  97. assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
  98. Kind != Option::GroupClass) &&
  99. "Special options should be defined first!");
  100. }
  101. // Check that options are in order.
  102. for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
  103. if (!(getInfo(i) < getInfo(i + 1))) {
  104. getOption(i).dump();
  105. getOption(i + 1).dump();
  106. llvm_unreachable("Options are not in order!");
  107. }
  108. }
  109. #endif
  110. }
  111. void OptTable::buildPrefixChars() {
  112. assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
  113. // Build prefix chars.
  114. for (const StringLiteral &Prefix : getPrefixesUnion()) {
  115. for (char C : Prefix)
  116. if (!is_contained(PrefixChars, C))
  117. PrefixChars.push_back(C);
  118. }
  119. }
  120. OptTable::~OptTable() = default;
  121. const Option OptTable::getOption(OptSpecifier Opt) const {
  122. unsigned id = Opt.getID();
  123. if (id == 0)
  124. return Option(nullptr, nullptr);
  125. assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
  126. return Option(&getInfo(id), this);
  127. }
  128. static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
  129. if (Arg == "-")
  130. return true;
  131. for (const StringRef &Prefix : Prefixes)
  132. if (Arg.startswith(Prefix))
  133. return false;
  134. return true;
  135. }
  136. /// \returns Matched size. 0 means no match.
  137. static unsigned matchOption(const OptTable::Info *I, StringRef Str,
  138. bool IgnoreCase) {
  139. for (auto Prefix : I->Prefixes) {
  140. if (Str.startswith(Prefix)) {
  141. StringRef Rest = Str.substr(Prefix.size());
  142. bool Matched = IgnoreCase ? Rest.startswith_insensitive(I->Name)
  143. : Rest.startswith(I->Name);
  144. if (Matched)
  145. return Prefix.size() + StringRef(I->Name).size();
  146. }
  147. }
  148. return 0;
  149. }
  150. // Returns true if one of the Prefixes + In.Names matches Option
  151. static bool optionMatches(const OptTable::Info &In, StringRef Option) {
  152. for (auto Prefix : In.Prefixes)
  153. if (Option.endswith(In.Name))
  154. if (Option.slice(0, Option.size() - In.Name.size()) == Prefix)
  155. return true;
  156. return false;
  157. }
  158. // This function is for flag value completion.
  159. // Eg. When "-stdlib=" and "l" was passed to this function, it will return
  160. // appropiriate values for stdlib, which starts with l.
  161. std::vector<std::string>
  162. OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
  163. // Search all options and return possible values.
  164. for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
  165. const Info &In = OptionInfos[I];
  166. if (!In.Values || !optionMatches(In, Option))
  167. continue;
  168. SmallVector<StringRef, 8> Candidates;
  169. StringRef(In.Values).split(Candidates, ",", -1, false);
  170. std::vector<std::string> Result;
  171. for (StringRef Val : Candidates)
  172. if (Val.startswith(Arg) && Arg.compare(Val))
  173. Result.push_back(std::string(Val));
  174. return Result;
  175. }
  176. return {};
  177. }
  178. std::vector<std::string>
  179. OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const {
  180. std::vector<std::string> Ret;
  181. for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
  182. const Info &In = OptionInfos[I];
  183. if (In.Prefixes.empty() || (!In.HelpText && !In.GroupID))
  184. continue;
  185. if (In.Flags & DisableFlags)
  186. continue;
  187. for (auto Prefix : In.Prefixes) {
  188. std::string S = (Prefix + In.Name + "\t").str();
  189. if (In.HelpText)
  190. S += In.HelpText;
  191. if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t")
  192. Ret.push_back(S);
  193. }
  194. }
  195. return Ret;
  196. }
  197. unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
  198. unsigned FlagsToInclude, unsigned FlagsToExclude,
  199. unsigned MinimumLength,
  200. unsigned MaximumDistance) const {
  201. assert(!Option.empty());
  202. // Consider each [option prefix + option name] pair as a candidate, finding
  203. // the closest match.
  204. unsigned BestDistance =
  205. MaximumDistance == UINT_MAX ? UINT_MAX : MaximumDistance + 1;
  206. SmallString<16> Candidate;
  207. SmallString<16> NormalizedName;
  208. for (const Info &CandidateInfo :
  209. ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
  210. StringRef CandidateName = CandidateInfo.Name;
  211. // We can eliminate some option prefix/name pairs as candidates right away:
  212. // * Ignore option candidates with empty names, such as "--", or names
  213. // that do not meet the minimum length.
  214. if (CandidateName.size() < MinimumLength)
  215. continue;
  216. // * If FlagsToInclude were specified, ignore options that don't include
  217. // those flags.
  218. if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
  219. continue;
  220. // * Ignore options that contain the FlagsToExclude.
  221. if (CandidateInfo.Flags & FlagsToExclude)
  222. continue;
  223. // * Ignore positional argument option candidates (which do not
  224. // have prefixes).
  225. if (CandidateInfo.Prefixes.empty())
  226. continue;
  227. // Now check if the candidate ends with a character commonly used when
  228. // delimiting an option from its value, such as '=' or ':'. If it does,
  229. // attempt to split the given option based on that delimiter.
  230. char Last = CandidateName.back();
  231. bool CandidateHasDelimiter = Last == '=' || Last == ':';
  232. StringRef RHS;
  233. if (CandidateHasDelimiter) {
  234. std::tie(NormalizedName, RHS) = Option.split(Last);
  235. if (Option.find(Last) == NormalizedName.size())
  236. NormalizedName += Last;
  237. } else
  238. NormalizedName = Option;
  239. // Consider each possible prefix for each candidate to find the most
  240. // appropriate one. For example, if a user asks for "--helm", suggest
  241. // "--help" over "-help".
  242. for (auto CandidatePrefix : CandidateInfo.Prefixes) {
  243. // If Candidate and NormalizedName have more than 'BestDistance'
  244. // characters of difference, no need to compute the edit distance, it's
  245. // going to be greater than BestDistance. Don't bother computing Candidate
  246. // at all.
  247. size_t CandidateSize = CandidatePrefix.size() + CandidateName.size(),
  248. NormalizedSize = NormalizedName.size();
  249. size_t AbsDiff = CandidateSize > NormalizedSize
  250. ? CandidateSize - NormalizedSize
  251. : NormalizedSize - CandidateSize;
  252. if (AbsDiff > BestDistance) {
  253. continue;
  254. }
  255. Candidate = CandidatePrefix;
  256. Candidate += CandidateName;
  257. unsigned Distance = StringRef(Candidate).edit_distance(
  258. NormalizedName, /*AllowReplacements=*/true,
  259. /*MaxEditDistance=*/BestDistance);
  260. if (RHS.empty() && CandidateHasDelimiter) {
  261. // The Candidate ends with a = or : delimiter, but the option passed in
  262. // didn't contain the delimiter (or doesn't have anything after it).
  263. // In that case, penalize the correction: `-nodefaultlibs` is more
  264. // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
  265. // though both have an unmodified editing distance of 1, since the
  266. // latter would need an argument.
  267. ++Distance;
  268. }
  269. if (Distance < BestDistance) {
  270. BestDistance = Distance;
  271. NearestString = (Candidate + RHS).str();
  272. }
  273. }
  274. }
  275. return BestDistance;
  276. }
  277. // Parse a single argument, return the new argument, and update Index. If
  278. // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will
  279. // be updated to "-bc". This overload does not support
  280. // FlagsToInclude/FlagsToExclude or case insensitive options.
  281. std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args,
  282. unsigned &Index) const {
  283. // Anything that doesn't start with PrefixesUnion is an input, as is '-'
  284. // itself.
  285. const char *CStr = Args.getArgString(Index);
  286. StringRef Str(CStr);
  287. if (isInput(getPrefixesUnion(), Str))
  288. return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr);
  289. const Info *End = OptionInfos.data() + OptionInfos.size();
  290. StringRef Name = Str.ltrim(PrefixChars);
  291. const Info *Start =
  292. std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name);
  293. const Info *Fallback = nullptr;
  294. unsigned Prev = Index;
  295. // Search for the option which matches Str.
  296. for (; Start != End; ++Start) {
  297. unsigned ArgSize = matchOption(Start, Str, IgnoreCase);
  298. if (!ArgSize)
  299. continue;
  300. Option Opt(Start, this);
  301. if (std::unique_ptr<Arg> A =
  302. Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
  303. /*GroupedShortOption=*/false, Index))
  304. return A;
  305. // If Opt is a Flag of length 2 (e.g. "-a"), we know it is a prefix of
  306. // the current argument (e.g. "-abc"). Match it as a fallback if no longer
  307. // option (e.g. "-ab") exists.
  308. if (ArgSize == 2 && Opt.getKind() == Option::FlagClass)
  309. Fallback = Start;
  310. // Otherwise, see if the argument is missing.
  311. if (Prev != Index)
  312. return nullptr;
  313. }
  314. if (Fallback) {
  315. Option Opt(Fallback, this);
  316. // Check that the last option isn't a flag wrongly given an argument.
  317. if (Str[2] == '=')
  318. return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
  319. CStr);
  320. if (std::unique_ptr<Arg> A = Opt.accept(
  321. Args, Str.substr(0, 2), /*GroupedShortOption=*/true, Index)) {
  322. Args.replaceArgString(Index, Twine('-') + Str.substr(2));
  323. return A;
  324. }
  325. }
  326. // In the case of an incorrect short option extract the character and move to
  327. // the next one.
  328. if (Str[1] != '-') {
  329. CStr = Args.MakeArgString(Str.substr(0, 2));
  330. Args.replaceArgString(Index, Twine('-') + Str.substr(2));
  331. return std::make_unique<Arg>(getOption(UnknownOptionID), CStr, Index, CStr);
  332. }
  333. return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++, CStr);
  334. }
  335. std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
  336. unsigned FlagsToInclude,
  337. unsigned FlagsToExclude) const {
  338. unsigned Prev = Index;
  339. StringRef Str = Args.getArgString(Index);
  340. // Anything that doesn't start with PrefixesUnion is an input, as is '-'
  341. // itself.
  342. if (isInput(getPrefixesUnion(), Str))
  343. return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
  344. Str.data());
  345. const Info *Start = OptionInfos.data() + FirstSearchableIndex;
  346. const Info *End = OptionInfos.data() + OptionInfos.size();
  347. StringRef Name = Str.ltrim(PrefixChars);
  348. // Search for the first next option which could be a prefix.
  349. Start = std::lower_bound(Start, End, Name);
  350. // Options are stored in sorted order, with '\0' at the end of the
  351. // alphabet. Since the only options which can accept a string must
  352. // prefix it, we iteratively search for the next option which could
  353. // be a prefix.
  354. //
  355. // FIXME: This is searching much more than necessary, but I am
  356. // blanking on the simplest way to make it fast. We can solve this
  357. // problem when we move to TableGen.
  358. for (; Start != End; ++Start) {
  359. unsigned ArgSize = 0;
  360. // Scan for first option which is a proper prefix.
  361. for (; Start != End; ++Start)
  362. if ((ArgSize = matchOption(Start, Str, IgnoreCase)))
  363. break;
  364. if (Start == End)
  365. break;
  366. Option Opt(Start, this);
  367. if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude))
  368. continue;
  369. if (Opt.hasFlag(FlagsToExclude))
  370. continue;
  371. // See if this option matches.
  372. if (std::unique_ptr<Arg> A =
  373. Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
  374. /*GroupedShortOption=*/false, Index))
  375. return A;
  376. // Otherwise, see if this argument was missing values.
  377. if (Prev != Index)
  378. return nullptr;
  379. }
  380. // If we failed to find an option and this arg started with /, then it's
  381. // probably an input path.
  382. if (Str[0] == '/')
  383. return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
  384. Str.data());
  385. return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
  386. Str.data());
  387. }
  388. InputArgList OptTable::ParseArgs(ArrayRef<const char *> ArgArr,
  389. unsigned &MissingArgIndex,
  390. unsigned &MissingArgCount,
  391. unsigned FlagsToInclude,
  392. unsigned FlagsToExclude) const {
  393. InputArgList Args(ArgArr.begin(), ArgArr.end());
  394. // FIXME: Handle '@' args (or at least error on them).
  395. MissingArgIndex = MissingArgCount = 0;
  396. unsigned Index = 0, End = ArgArr.size();
  397. while (Index < End) {
  398. // Ingore nullptrs, they are response file's EOL markers
  399. if (Args.getArgString(Index) == nullptr) {
  400. ++Index;
  401. continue;
  402. }
  403. // Ignore empty arguments (other things may still take them as arguments).
  404. StringRef Str = Args.getArgString(Index);
  405. if (Str == "") {
  406. ++Index;
  407. continue;
  408. }
  409. unsigned Prev = Index;
  410. std::unique_ptr<Arg> A = GroupedShortOptions
  411. ? parseOneArgGrouped(Args, Index)
  412. : ParseOneArg(Args, Index, FlagsToInclude, FlagsToExclude);
  413. assert((Index > Prev || GroupedShortOptions) &&
  414. "Parser failed to consume argument.");
  415. // Check for missing argument error.
  416. if (!A) {
  417. assert(Index >= End && "Unexpected parser error.");
  418. assert(Index - Prev - 1 && "No missing arguments!");
  419. MissingArgIndex = Prev;
  420. MissingArgCount = Index - Prev - 1;
  421. break;
  422. }
  423. Args.append(A.release());
  424. }
  425. return Args;
  426. }
  427. InputArgList OptTable::parseArgs(int Argc, char *const *Argv,
  428. OptSpecifier Unknown, StringSaver &Saver,
  429. function_ref<void(StringRef)> ErrorFn) const {
  430. SmallVector<const char *, 0> NewArgv;
  431. // The environment variable specifies initial options which can be overridden
  432. // by commnad line options.
  433. cl::expandResponseFiles(Argc, Argv, EnvVar, Saver, NewArgv);
  434. unsigned MAI, MAC;
  435. opt::InputArgList Args = ParseArgs(ArrayRef(NewArgv), MAI, MAC);
  436. if (MAC)
  437. ErrorFn((Twine(Args.getArgString(MAI)) + ": missing argument").str());
  438. // For each unknwon option, call ErrorFn with a formatted error message. The
  439. // message includes a suggested alternative option spelling if available.
  440. std::string Nearest;
  441. for (const opt::Arg *A : Args.filtered(Unknown)) {
  442. std::string Spelling = A->getAsString(Args);
  443. if (findNearest(Spelling, Nearest) > 1)
  444. ErrorFn("unknown argument '" + Spelling + "'");
  445. else
  446. ErrorFn("unknown argument '" + Spelling + "', did you mean '" + Nearest +
  447. "'?");
  448. }
  449. return Args;
  450. }
  451. static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
  452. const Option O = Opts.getOption(Id);
  453. std::string Name = O.getPrefixedName();
  454. // Add metavar, if used.
  455. switch (O.getKind()) {
  456. case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
  457. llvm_unreachable("Invalid option with help text.");
  458. case Option::MultiArgClass:
  459. if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) {
  460. // For MultiArgs, metavar is full list of all argument names.
  461. Name += ' ';
  462. Name += MetaVarName;
  463. }
  464. else {
  465. // For MultiArgs<N>, if metavar not supplied, print <value> N times.
  466. for (unsigned i=0, e=O.getNumArgs(); i< e; ++i) {
  467. Name += " <value>";
  468. }
  469. }
  470. break;
  471. case Option::FlagClass:
  472. break;
  473. case Option::ValuesClass:
  474. break;
  475. case Option::SeparateClass: case Option::JoinedOrSeparateClass:
  476. case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass:
  477. Name += ' ';
  478. [[fallthrough]];
  479. case Option::JoinedClass: case Option::CommaJoinedClass:
  480. case Option::JoinedAndSeparateClass:
  481. if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
  482. Name += MetaVarName;
  483. else
  484. Name += "<value>";
  485. break;
  486. }
  487. return Name;
  488. }
  489. namespace {
  490. struct OptionInfo {
  491. std::string Name;
  492. StringRef HelpText;
  493. };
  494. } // namespace
  495. static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
  496. std::vector<OptionInfo> &OptionHelp) {
  497. OS << Title << ":\n";
  498. // Find the maximum option length.
  499. unsigned OptionFieldWidth = 0;
  500. for (const OptionInfo &Opt : OptionHelp) {
  501. // Limit the amount of padding we are willing to give up for alignment.
  502. unsigned Length = Opt.Name.size();
  503. if (Length <= 23)
  504. OptionFieldWidth = std::max(OptionFieldWidth, Length);
  505. }
  506. const unsigned InitialPad = 2;
  507. for (const OptionInfo &Opt : OptionHelp) {
  508. const std::string &Option = Opt.Name;
  509. int Pad = OptionFieldWidth - int(Option.size());
  510. OS.indent(InitialPad) << Option;
  511. // Break on long option names.
  512. if (Pad < 0) {
  513. OS << "\n";
  514. Pad = OptionFieldWidth + InitialPad;
  515. }
  516. OS.indent(Pad + 1) << Opt.HelpText << '\n';
  517. }
  518. }
  519. static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
  520. unsigned GroupID = Opts.getOptionGroupID(Id);
  521. // If not in a group, return the default help group.
  522. if (!GroupID)
  523. return "OPTIONS";
  524. // Abuse the help text of the option groups to store the "help group"
  525. // name.
  526. //
  527. // FIXME: Split out option groups.
  528. if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
  529. return GroupHelp;
  530. // Otherwise keep looking.
  531. return getOptionHelpGroup(Opts, GroupID);
  532. }
  533. void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
  534. bool ShowHidden, bool ShowAllAliases) const {
  535. printHelp(OS, Usage, Title, /*Include*/ 0, /*Exclude*/
  536. (ShowHidden ? 0 : HelpHidden), ShowAllAliases);
  537. }
  538. void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
  539. unsigned FlagsToInclude, unsigned FlagsToExclude,
  540. bool ShowAllAliases) const {
  541. OS << "OVERVIEW: " << Title << "\n\n";
  542. OS << "USAGE: " << Usage << "\n\n";
  543. // Render help text into a map of group-name to a list of (option, help)
  544. // pairs.
  545. std::map<std::string, std::vector<OptionInfo>> GroupedOptionHelp;
  546. for (unsigned Id = 1, e = getNumOptions() + 1; Id != e; ++Id) {
  547. // FIXME: Split out option groups.
  548. if (getOptionKind(Id) == Option::GroupClass)
  549. continue;
  550. unsigned Flags = getInfo(Id).Flags;
  551. if (FlagsToInclude && !(Flags & FlagsToInclude))
  552. continue;
  553. if (Flags & FlagsToExclude)
  554. continue;
  555. // If an alias doesn't have a help text, show a help text for the aliased
  556. // option instead.
  557. const char *HelpText = getOptionHelpText(Id);
  558. if (!HelpText && ShowAllAliases) {
  559. const Option Alias = getOption(Id).getAlias();
  560. if (Alias.isValid())
  561. HelpText = getOptionHelpText(Alias.getID());
  562. }
  563. if (HelpText && (strlen(HelpText) != 0)) {
  564. const char *HelpGroup = getOptionHelpGroup(*this, Id);
  565. const std::string &OptName = getOptionHelpName(*this, Id);
  566. GroupedOptionHelp[HelpGroup].push_back({OptName, HelpText});
  567. }
  568. }
  569. for (auto& OptionGroup : GroupedOptionHelp) {
  570. if (OptionGroup.first != GroupedOptionHelp.begin()->first)
  571. OS << "\n";
  572. PrintHelpOptionList(OS, OptionGroup.first, OptionGroup.second);
  573. }
  574. OS.flush();
  575. }
  576. GenericOptTable::GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
  577. : OptTable(OptionInfos, IgnoreCase) {
  578. std::set<StringLiteral> TmpPrefixesUnion;
  579. for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
  580. TmpPrefixesUnion.insert(Info.Prefixes.begin(), Info.Prefixes.end());
  581. PrefixesUnionBuffer.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
  582. buildPrefixChars();
  583. }