1 | //===- Option.cpp - Abstract Driver Options -------------------------------===// |
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/StringRef.h" |
10 | #include "llvm/ADT/Twine.h" |
11 | #include "llvm/Config/llvm-config.h" |
12 | #include "llvm/Option/Arg.h" |
13 | #include "llvm/Option/ArgList.h" |
14 | #include "llvm/Option/Option.h" |
15 | #include "llvm/Option/OptTable.h" |
16 | #include "llvm/Support/Compiler.h" |
17 | #include "llvm/Support/Debug.h" |
18 | #include "llvm/Support/ErrorHandling.h" |
19 | #include "llvm/Support/raw_ostream.h" |
20 | #include <cassert> |
21 | #include <cstring> |
22 | |
23 | using namespace llvm; |
24 | using namespace llvm::opt; |
25 | |
26 | Option::Option(const OptTable::Info *info, const OptTable *owner) |
27 | : Info(info), Owner(owner) { |
28 | // Multi-level aliases are not supported. This just simplifies option |
29 | // tracking, it is not an inherent limitation. |
30 | assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) && |
31 | "Multi-level aliases are not supported." ); |
32 | |
33 | if (Info && getAliasArgs()) { |
34 | assert(getAlias().isValid() && "Only alias options can have alias args." ); |
35 | assert(getKind() == FlagClass && "Only Flag aliases can have alias args." ); |
36 | assert(getAlias().getKind() != FlagClass && |
37 | "Cannot provide alias args to a flag option." ); |
38 | } |
39 | } |
40 | |
41 | void Option::print(raw_ostream &O, bool AddNewLine) const { |
42 | O << "<" ; |
43 | switch (getKind()) { |
44 | #define P(N) case N: O << #N; break |
45 | P(GroupClass); |
46 | P(InputClass); |
47 | P(UnknownClass); |
48 | P(FlagClass); |
49 | P(JoinedClass); |
50 | P(ValuesClass); |
51 | P(SeparateClass); |
52 | P(CommaJoinedClass); |
53 | P(MultiArgClass); |
54 | P(JoinedOrSeparateClass); |
55 | P(JoinedAndSeparateClass); |
56 | P(RemainingArgsClass); |
57 | P(RemainingArgsJoinedClass); |
58 | #undef P |
59 | } |
60 | |
61 | if (!Info->Prefixes.empty()) { |
62 | O << " Prefixes:[" ; |
63 | for (size_t I = 0, N = Info->Prefixes.size(); I != N; ++I) |
64 | O << '"' << Info->Prefixes[I] << (I == N - 1 ? "\"" : "\", " ); |
65 | O << ']'; |
66 | } |
67 | |
68 | O << " Name:\"" << getName() << '"'; |
69 | |
70 | const Option Group = getGroup(); |
71 | if (Group.isValid()) { |
72 | O << " Group:" ; |
73 | Group.print(O, /*AddNewLine=*/false); |
74 | } |
75 | |
76 | const Option Alias = getAlias(); |
77 | if (Alias.isValid()) { |
78 | O << " Alias:" ; |
79 | Alias.print(O, /*AddNewLine=*/false); |
80 | } |
81 | |
82 | if (getKind() == MultiArgClass) |
83 | O << " NumArgs:" << getNumArgs(); |
84 | |
85 | O << ">" ; |
86 | if (AddNewLine) |
87 | O << "\n" ; |
88 | } |
89 | |
90 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
91 | LLVM_DUMP_METHOD void Option::dump() const { print(dbgs()); } |
92 | #endif |
93 | |
94 | bool Option::matches(OptSpecifier Opt) const { |
95 | // Aliases are never considered in matching, look through them. |
96 | const Option Alias = getAlias(); |
97 | if (Alias.isValid()) |
98 | return Alias.matches(Opt); |
99 | |
100 | // Check exact match. |
101 | if (getID() == Opt.getID()) |
102 | return true; |
103 | |
104 | const Option Group = getGroup(); |
105 | if (Group.isValid()) |
106 | return Group.matches(Opt); |
107 | return false; |
108 | } |
109 | |
110 | std::unique_ptr<Arg> Option::acceptInternal(const ArgList &Args, |
111 | StringRef Spelling, |
112 | unsigned &Index) const { |
113 | const size_t SpellingSize = Spelling.size(); |
114 | const size_t ArgStringSize = StringRef(Args.getArgString(Index)).size(); |
115 | switch (getKind()) { |
116 | case FlagClass: { |
117 | if (SpellingSize != ArgStringSize) |
118 | return nullptr; |
119 | return std::make_unique<Arg>(args: *this, args&: Spelling, args: Index++); |
120 | } |
121 | case JoinedClass: { |
122 | const char *Value = Args.getArgString(Index) + SpellingSize; |
123 | return std::make_unique<Arg>(args: *this, args&: Spelling, args: Index++, args&: Value); |
124 | } |
125 | case CommaJoinedClass: { |
126 | // Always matches. |
127 | const char *Str = Args.getArgString(Index) + SpellingSize; |
128 | auto A = std::make_unique<Arg>(args: *this, args&: Spelling, args: Index++); |
129 | |
130 | // Parse out the comma separated values. |
131 | const char *Prev = Str; |
132 | for (;; ++Str) { |
133 | char c = *Str; |
134 | |
135 | if (!c || c == ',') { |
136 | if (Prev != Str) { |
137 | char *Value = new char[Str - Prev + 1]; |
138 | memcpy(dest: Value, src: Prev, n: Str - Prev); |
139 | Value[Str - Prev] = '\0'; |
140 | A->getValues().push_back(Elt: Value); |
141 | } |
142 | |
143 | if (!c) |
144 | break; |
145 | |
146 | Prev = Str + 1; |
147 | } |
148 | } |
149 | A->setOwnsValues(true); |
150 | |
151 | return A; |
152 | } |
153 | case SeparateClass: |
154 | // Matches iff this is an exact match. |
155 | if (SpellingSize != ArgStringSize) |
156 | return nullptr; |
157 | |
158 | Index += 2; |
159 | if (Index > Args.getNumInputArgStrings() || |
160 | Args.getArgString(Index: Index - 1) == nullptr) |
161 | return nullptr; |
162 | |
163 | return std::make_unique<Arg>(args: *this, args&: Spelling, args: Index - 2, |
164 | args: Args.getArgString(Index: Index - 1)); |
165 | case MultiArgClass: { |
166 | // Matches iff this is an exact match. |
167 | if (SpellingSize != ArgStringSize) |
168 | return nullptr; |
169 | |
170 | Index += 1 + getNumArgs(); |
171 | if (Index > Args.getNumInputArgStrings()) |
172 | return nullptr; |
173 | |
174 | auto A = std::make_unique<Arg>(args: *this, args&: Spelling, args: Index - 1 - getNumArgs(), |
175 | args: Args.getArgString(Index: Index - getNumArgs())); |
176 | for (unsigned i = 1; i != getNumArgs(); ++i) |
177 | A->getValues().push_back(Elt: Args.getArgString(Index: Index - getNumArgs() + i)); |
178 | return A; |
179 | } |
180 | case JoinedOrSeparateClass: { |
181 | // If this is not an exact match, it is a joined arg. |
182 | if (SpellingSize != ArgStringSize) { |
183 | const char *Value = Args.getArgString(Index) + SpellingSize; |
184 | return std::make_unique<Arg>(args: *this, args&: Spelling, args: Index++, args&: Value); |
185 | } |
186 | |
187 | // Otherwise it must be separate. |
188 | Index += 2; |
189 | if (Index > Args.getNumInputArgStrings() || |
190 | Args.getArgString(Index: Index - 1) == nullptr) |
191 | return nullptr; |
192 | |
193 | return std::make_unique<Arg>(args: *this, args&: Spelling, args: Index - 2, |
194 | args: Args.getArgString(Index: Index - 1)); |
195 | } |
196 | case JoinedAndSeparateClass: |
197 | // Always matches. |
198 | Index += 2; |
199 | if (Index > Args.getNumInputArgStrings() || |
200 | Args.getArgString(Index: Index - 1) == nullptr) |
201 | return nullptr; |
202 | |
203 | return std::make_unique<Arg>(args: *this, args&: Spelling, args: Index - 2, |
204 | args: Args.getArgString(Index: Index - 2) + SpellingSize, |
205 | args: Args.getArgString(Index: Index - 1)); |
206 | case RemainingArgsClass: { |
207 | // Matches iff this is an exact match. |
208 | if (SpellingSize != ArgStringSize) |
209 | return nullptr; |
210 | auto A = std::make_unique<Arg>(args: *this, args&: Spelling, args: Index++); |
211 | while (Index < Args.getNumInputArgStrings() && |
212 | Args.getArgString(Index) != nullptr) |
213 | A->getValues().push_back(Elt: Args.getArgString(Index: Index++)); |
214 | return A; |
215 | } |
216 | case RemainingArgsJoinedClass: { |
217 | auto A = std::make_unique<Arg>(args: *this, args&: Spelling, args&: Index); |
218 | if (SpellingSize != ArgStringSize) { |
219 | // An inexact match means there is a joined arg. |
220 | A->getValues().push_back(Elt: Args.getArgString(Index) + SpellingSize); |
221 | } |
222 | Index++; |
223 | while (Index < Args.getNumInputArgStrings() && |
224 | Args.getArgString(Index) != nullptr) |
225 | A->getValues().push_back(Elt: Args.getArgString(Index: Index++)); |
226 | return A; |
227 | } |
228 | |
229 | default: |
230 | llvm_unreachable("Invalid option kind!" ); |
231 | } |
232 | } |
233 | |
234 | std::unique_ptr<Arg> Option::accept(const ArgList &Args, StringRef CurArg, |
235 | bool GroupedShortOption, |
236 | unsigned &Index) const { |
237 | auto A(GroupedShortOption && getKind() == FlagClass |
238 | ? std::make_unique<Arg>(args: *this, args&: CurArg, args&: Index) |
239 | : acceptInternal(Args, Spelling: CurArg, Index)); |
240 | if (!A) |
241 | return nullptr; |
242 | |
243 | const Option &UnaliasedOption = getUnaliasedOption(); |
244 | if (getID() == UnaliasedOption.getID()) |
245 | return A; |
246 | |
247 | // "A" is an alias for a different flag. For most clients it's more convenient |
248 | // if this function returns unaliased Args, so create an unaliased arg for |
249 | // returning. |
250 | |
251 | // This creates a completely new Arg object for the unaliased Arg because |
252 | // the alias and the unaliased arg can have different Kinds and different |
253 | // Values (due to AliasArgs<>). |
254 | |
255 | // Get the spelling from the unaliased option. |
256 | StringRef UnaliasedSpelling = Args.MakeArgString( |
257 | Str: Twine(UnaliasedOption.getPrefix()) + Twine(UnaliasedOption.getName())); |
258 | |
259 | // It's a bit weird that aliased and unaliased arg share one index, but |
260 | // the index is mostly use as a memory optimization in render(). |
261 | // Due to this, ArgList::getArgString(A->getIndex()) will return the spelling |
262 | // of the aliased arg always, while A->getSpelling() returns either the |
263 | // unaliased or the aliased arg, depending on which Arg object it's called on. |
264 | auto UnaliasedA = |
265 | std::make_unique<Arg>(args: UnaliasedOption, args&: UnaliasedSpelling, args: A->getIndex()); |
266 | Arg *RawA = A.get(); |
267 | UnaliasedA->setAlias(std::move(A)); |
268 | |
269 | if (getKind() != FlagClass) { |
270 | // Values are usually owned by the ArgList. The exception are |
271 | // CommaJoined flags, where the Arg owns the values. For aliased flags, |
272 | // make the unaliased Arg the owner of the values. |
273 | // FIXME: There aren't many uses of CommaJoined -- try removing |
274 | // CommaJoined in favor of just calling StringRef::split(',') instead. |
275 | UnaliasedA->getValues() = RawA->getValues(); |
276 | UnaliasedA->setOwnsValues(RawA->getOwnsValues()); |
277 | RawA->setOwnsValues(false); |
278 | return UnaliasedA; |
279 | } |
280 | |
281 | // FlagClass aliases can have AliasArgs<>; add those to the unaliased arg. |
282 | if (const char *Val = getAliasArgs()) { |
283 | while (*Val != '\0') { |
284 | UnaliasedA->getValues().push_back(Elt: Val); |
285 | |
286 | // Move past the '\0' to the next argument. |
287 | Val += strlen(s: Val) + 1; |
288 | } |
289 | } |
290 | if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs()) |
291 | // A Flag alias for a Joined option must provide an argument. |
292 | UnaliasedA->getValues().push_back(Elt: "" ); |
293 | return UnaliasedA; |
294 | } |
295 | |