ArgList.cpp revision 360784
1//===- ArgList.cpp - Argument List Management -----------------------------===//
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
9#include "llvm/ADT/ArrayRef.h"
10#include "llvm/ADT/None.h"
11#include "llvm/ADT/SmallVector.h"
12#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/Twine.h"
15#include "llvm/Config/llvm-config.h"
16#include "llvm/Option/Arg.h"
17#include "llvm/Option/ArgList.h"
18#include "llvm/Option/Option.h"
19#include "llvm/Option/OptSpecifier.h"
20#include "llvm/Support/Compiler.h"
21#include "llvm/Support/Debug.h"
22#include "llvm/Support/raw_ostream.h"
23#include <algorithm>
24#include <cassert>
25#include <memory>
26#include <string>
27#include <utility>
28#include <vector>
29
30using namespace llvm;
31using namespace llvm::opt;
32
33void ArgList::append(Arg *A) {
34  Args.push_back(A);
35
36  // Update ranges for the option and all of its groups.
37  for (Option O = A->getOption().getUnaliasedOption(); O.isValid();
38       O = O.getGroup()) {
39    auto &R =
40        OptRanges.insert(std::make_pair(O.getID(), emptyRange())).first->second;
41    R.first = std::min<unsigned>(R.first, Args.size() - 1);
42    R.second = Args.size();
43  }
44}
45
46void ArgList::eraseArg(OptSpecifier Id) {
47  // Zero out the removed entries but keep them around so that we don't
48  // need to invalidate OptRanges.
49  for (Arg *const &A : filtered(Id)) {
50    // Avoid the need for a non-const filtered iterator variant.
51    Arg **ArgsBegin = Args.data();
52    ArgsBegin[&A - ArgsBegin] = nullptr;
53  }
54  OptRanges.erase(Id.getID());
55}
56
57ArgList::OptRange
58ArgList::getRange(std::initializer_list<OptSpecifier> Ids) const {
59  OptRange R = emptyRange();
60  for (auto Id : Ids) {
61    auto I = OptRanges.find(Id.getID());
62    if (I != OptRanges.end()) {
63      R.first = std::min(R.first, I->second.first);
64      R.second = std::max(R.second, I->second.second);
65    }
66  }
67  // Map an empty {-1, 0} range to {0, 0} so it can be used to form iterators.
68  if (R.first == -1u)
69    R.first = 0;
70  return R;
71}
72
73bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
74  if (Arg *A = getLastArg(Pos, Neg))
75    return A->getOption().matches(Pos);
76  return Default;
77}
78
79bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg,
80                      bool Default) const {
81  if (Arg *A = getLastArg(Pos, PosAlias, Neg))
82    return A->getOption().matches(Pos) || A->getOption().matches(PosAlias);
83  return Default;
84}
85
86StringRef ArgList::getLastArgValue(OptSpecifier Id, StringRef Default) const {
87  if (Arg *A = getLastArg(Id))
88    return A->getValue();
89  return Default;
90}
91
92std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
93  SmallVector<const char *, 16> Values;
94  AddAllArgValues(Values, Id);
95  return std::vector<std::string>(Values.begin(), Values.end());
96}
97
98void ArgList::AddAllArgsExcept(ArgStringList &Output,
99                               ArrayRef<OptSpecifier> Ids,
100                               ArrayRef<OptSpecifier> ExcludeIds) const {
101  for (const Arg *Arg : *this) {
102    bool Excluded = false;
103    for (OptSpecifier Id : ExcludeIds) {
104      if (Arg->getOption().matches(Id)) {
105        Excluded = true;
106        break;
107      }
108    }
109    if (!Excluded) {
110      for (OptSpecifier Id : Ids) {
111        if (Arg->getOption().matches(Id)) {
112          Arg->claim();
113          Arg->render(*this, Output);
114          break;
115        }
116      }
117    }
118  }
119}
120
121/// This is a nicer interface when you don't have a list of Ids to exclude.
122void ArgList::AddAllArgs(ArgStringList &Output,
123                         ArrayRef<OptSpecifier> Ids) const {
124  ArrayRef<OptSpecifier> Exclude = None;
125  AddAllArgsExcept(Output, Ids, Exclude);
126}
127
128/// This 3-opt variant of AddAllArgs could be eliminated in favor of one
129/// that accepts a single specifier, given the above which accepts any number.
130void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
131                         OptSpecifier Id1, OptSpecifier Id2) const {
132  for (auto Arg: filtered(Id0, Id1, Id2)) {
133    Arg->claim();
134    Arg->render(*this, Output);
135  }
136}
137
138void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
139                              OptSpecifier Id1, OptSpecifier Id2) const {
140  for (auto Arg : filtered(Id0, Id1, Id2)) {
141    Arg->claim();
142    const auto &Values = Arg->getValues();
143    Output.append(Values.begin(), Values.end());
144  }
145}
146
147void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
148                                   const char *Translation,
149                                   bool Joined) const {
150  for (auto Arg: filtered(Id0)) {
151    Arg->claim();
152
153    if (Joined) {
154      Output.push_back(MakeArgString(StringRef(Translation) +
155                                     Arg->getValue(0)));
156    } else {
157      Output.push_back(Translation);
158      Output.push_back(Arg->getValue(0));
159    }
160  }
161}
162
163void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
164  for (auto *Arg : filtered(Id0))
165    Arg->claim();
166}
167
168void ArgList::ClaimAllArgs() const {
169  for (auto *Arg : *this)
170    if (!Arg->isClaimed())
171      Arg->claim();
172}
173
174const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
175                                              StringRef LHS,
176                                              StringRef RHS) const {
177  StringRef Cur = getArgString(Index);
178  if (Cur.size() == LHS.size() + RHS.size() &&
179      Cur.startswith(LHS) && Cur.endswith(RHS))
180    return Cur.data();
181
182  return MakeArgString(LHS + RHS);
183}
184
185void ArgList::print(raw_ostream &O) const {
186  for (Arg *A : *this) {
187    O << "* ";
188    A->print(O);
189  }
190}
191
192#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
193LLVM_DUMP_METHOD void ArgList::dump() const { print(dbgs()); }
194#endif
195
196void InputArgList::releaseMemory() {
197  // An InputArgList always owns its arguments.
198  for (Arg *A : *this)
199    delete A;
200}
201
202InputArgList::InputArgList(const char* const *ArgBegin,
203                           const char* const *ArgEnd)
204  : NumInputArgStrings(ArgEnd - ArgBegin) {
205  ArgStrings.append(ArgBegin, ArgEnd);
206}
207
208unsigned InputArgList::MakeIndex(StringRef String0) const {
209  unsigned Index = ArgStrings.size();
210
211  // Tuck away so we have a reliable const char *.
212  SynthesizedStrings.push_back(String0);
213  ArgStrings.push_back(SynthesizedStrings.back().c_str());
214
215  return Index;
216}
217
218unsigned InputArgList::MakeIndex(StringRef String0,
219                                 StringRef String1) const {
220  unsigned Index0 = MakeIndex(String0);
221  unsigned Index1 = MakeIndex(String1);
222  assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
223  (void) Index1;
224  return Index0;
225}
226
227const char *InputArgList::MakeArgStringRef(StringRef Str) const {
228  return getArgString(MakeIndex(Str));
229}
230
231DerivedArgList::DerivedArgList(const InputArgList &BaseArgs)
232    : BaseArgs(BaseArgs) {}
233
234const char *DerivedArgList::MakeArgStringRef(StringRef Str) const {
235  return BaseArgs.MakeArgString(Str);
236}
237
238void DerivedArgList::AddSynthesizedArg(Arg *A) {
239  SynthesizedArgs.push_back(std::unique_ptr<Arg>(A));
240}
241
242Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const {
243  SynthesizedArgs.push_back(
244      std::make_unique<Arg>(Opt, MakeArgString(Opt.getPrefix() + Opt.getName()),
245                       BaseArgs.MakeIndex(Opt.getName()), BaseArg));
246  return SynthesizedArgs.back().get();
247}
248
249Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
250                                       StringRef Value) const {
251  unsigned Index = BaseArgs.MakeIndex(Value);
252  SynthesizedArgs.push_back(
253      std::make_unique<Arg>(Opt, MakeArgString(Opt.getPrefix() + Opt.getName()),
254                       Index, BaseArgs.getArgString(Index), BaseArg));
255  return SynthesizedArgs.back().get();
256}
257
258Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
259                                     StringRef Value) const {
260  unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value);
261  SynthesizedArgs.push_back(
262      std::make_unique<Arg>(Opt, MakeArgString(Opt.getPrefix() + Opt.getName()),
263                       Index, BaseArgs.getArgString(Index + 1), BaseArg));
264  return SynthesizedArgs.back().get();
265}
266
267Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt,
268                                   StringRef Value) const {
269  unsigned Index = BaseArgs.MakeIndex((Opt.getName() + Value).str());
270  SynthesizedArgs.push_back(std::make_unique<Arg>(
271      Opt, MakeArgString(Opt.getPrefix() + Opt.getName()), Index,
272      BaseArgs.getArgString(Index) + Opt.getName().size(), BaseArg));
273  return SynthesizedArgs.back().get();
274}
275