1 //===--- Option.cpp - Abstract Driver Options -----------------------------===//
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/Option.h"
11
12 #include "clang/Driver/Arg.h"
13 #include "clang/Driver/ArgList.h"
14 #include "llvm/Support/raw_ostream.h"
15 #include "llvm/Support/ErrorHandling.h"
16 #include <cassert>
17 #include <algorithm>
18 using namespace clang::driver;
19
Option(OptionClass _Kind,OptSpecifier _ID,const char * _Name,const OptionGroup * _Group,const Option * _Alias)20 Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name,
21 const OptionGroup *_Group, const Option *_Alias)
22 : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias),
23 Unsupported(false), LinkerInput(false), NoOptAsInput(false),
24 DriverOption(false), NoArgumentUnused(false), NoForward(false) {
25
26 // Multi-level aliases are not supported, and alias options cannot
27 // have groups. This just simplifies option tracking, it is not an
28 // inherent limitation.
29 assert((!Alias || (!Alias->Alias && !Group)) &&
30 "Multi-level aliases and aliases with groups are unsupported.");
31
32 // Initialize rendering options based on the class.
33 switch (Kind) {
34 case GroupClass:
35 case InputClass:
36 case UnknownClass:
37 RenderStyle = RenderValuesStyle;
38 break;
39
40 case JoinedClass:
41 case JoinedAndSeparateClass:
42 RenderStyle = RenderJoinedStyle;
43 break;
44
45 case CommaJoinedClass:
46 RenderStyle = RenderCommaJoinedStyle;
47 break;
48
49 case FlagClass:
50 case SeparateClass:
51 case MultiArgClass:
52 case JoinedOrSeparateClass:
53 RenderStyle = RenderSeparateStyle;
54 break;
55 }
56 }
57
~Option()58 Option::~Option() {
59 }
60
dump() const61 void Option::dump() const {
62 llvm::errs() << "<";
63 switch (Kind) {
64 #define P(N) case N: llvm::errs() << #N; break
65 P(GroupClass);
66 P(InputClass);
67 P(UnknownClass);
68 P(FlagClass);
69 P(JoinedClass);
70 P(SeparateClass);
71 P(CommaJoinedClass);
72 P(MultiArgClass);
73 P(JoinedOrSeparateClass);
74 P(JoinedAndSeparateClass);
75 #undef P
76 }
77
78 llvm::errs() << " Name:\"" << Name << '"';
79
80 if (Group) {
81 llvm::errs() << " Group:";
82 Group->dump();
83 }
84
85 if (Alias) {
86 llvm::errs() << " Alias:";
87 Alias->dump();
88 }
89
90 if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this))
91 llvm::errs() << " NumArgs:" << MOA->getNumArgs();
92
93 llvm::errs() << ">\n";
94 }
95
matches(OptSpecifier Opt) const96 bool Option::matches(OptSpecifier Opt) const {
97 // Aliases are never considered in matching, look through them.
98 if (Alias)
99 return Alias->matches(Opt);
100
101 // Check exact match.
102 if (ID == Opt)
103 return true;
104
105 if (Group)
106 return Group->matches(Opt);
107 return false;
108 }
109
OptionGroup(OptSpecifier ID,const char * Name,const OptionGroup * Group)110 OptionGroup::OptionGroup(OptSpecifier ID, const char *Name,
111 const OptionGroup *Group)
112 : Option(Option::GroupClass, ID, Name, Group, 0) {
113 }
114
accept(const ArgList & Args,unsigned & Index) const115 Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const {
116 llvm_unreachable("accept() should never be called on an OptionGroup");
117 }
118
InputOption(OptSpecifier ID)119 InputOption::InputOption(OptSpecifier ID)
120 : Option(Option::InputClass, ID, "<input>", 0, 0) {
121 }
122
accept(const ArgList & Args,unsigned & Index) const123 Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const {
124 llvm_unreachable("accept() should never be called on an InputOption");
125 }
126
UnknownOption(OptSpecifier ID)127 UnknownOption::UnknownOption(OptSpecifier ID)
128 : Option(Option::UnknownClass, ID, "<unknown>", 0, 0) {
129 }
130
accept(const ArgList & Args,unsigned & Index) const131 Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const {
132 llvm_unreachable("accept() should never be called on an UnknownOption");
133 }
134
FlagOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)135 FlagOption::FlagOption(OptSpecifier ID, const char *Name,
136 const OptionGroup *Group, const Option *Alias)
137 : Option(Option::FlagClass, ID, Name, Group, Alias) {
138 }
139
accept(const ArgList & Args,unsigned & Index) const140 Arg *FlagOption::accept(const ArgList &Args, unsigned &Index) const {
141 // Matches iff this is an exact match.
142 // FIXME: Avoid strlen.
143 if (getName().size() != strlen(Args.getArgString(Index)))
144 return 0;
145
146 return new Arg(getUnaliasedOption(), Index++);
147 }
148
JoinedOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)149 JoinedOption::JoinedOption(OptSpecifier ID, const char *Name,
150 const OptionGroup *Group, const Option *Alias)
151 : Option(Option::JoinedClass, ID, Name, Group, Alias) {
152 }
153
accept(const ArgList & Args,unsigned & Index) const154 Arg *JoinedOption::accept(const ArgList &Args, unsigned &Index) const {
155 // Always matches.
156 const char *Value = Args.getArgString(Index) + getName().size();
157 return new Arg(getUnaliasedOption(), Index++, Value);
158 }
159
CommaJoinedOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)160 CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name,
161 const OptionGroup *Group,
162 const Option *Alias)
163 : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) {
164 }
165
accept(const ArgList & Args,unsigned & Index) const166 Arg *CommaJoinedOption::accept(const ArgList &Args,
167 unsigned &Index) const {
168 // Always matches.
169 const char *Str = Args.getArgString(Index) + getName().size();
170 Arg *A = new Arg(getUnaliasedOption(), Index++);
171
172 // Parse out the comma separated values.
173 const char *Prev = Str;
174 for (;; ++Str) {
175 char c = *Str;
176
177 if (!c || c == ',') {
178 if (Prev != Str) {
179 char *Value = new char[Str - Prev + 1];
180 memcpy(Value, Prev, Str - Prev);
181 Value[Str - Prev] = '\0';
182 A->getValues().push_back(Value);
183 }
184
185 if (!c)
186 break;
187
188 Prev = Str + 1;
189 }
190 }
191 A->setOwnsValues(true);
192
193 return A;
194 }
195
SeparateOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)196 SeparateOption::SeparateOption(OptSpecifier ID, const char *Name,
197 const OptionGroup *Group, const Option *Alias)
198 : Option(Option::SeparateClass, ID, Name, Group, Alias) {
199 }
200
accept(const ArgList & Args,unsigned & Index) const201 Arg *SeparateOption::accept(const ArgList &Args, unsigned &Index) const {
202 // Matches iff this is an exact match.
203 // FIXME: Avoid strlen.
204 if (getName().size() != strlen(Args.getArgString(Index)))
205 return 0;
206
207 Index += 2;
208 if (Index > Args.getNumInputArgStrings())
209 return 0;
210
211 return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
212 }
213
MultiArgOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias,unsigned _NumArgs)214 MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name,
215 const OptionGroup *Group, const Option *Alias,
216 unsigned _NumArgs)
217 : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) {
218 assert(NumArgs > 1 && "Invalid MultiArgOption!");
219 }
220
accept(const ArgList & Args,unsigned & Index) const221 Arg *MultiArgOption::accept(const ArgList &Args, unsigned &Index) const {
222 // Matches iff this is an exact match.
223 // FIXME: Avoid strlen.
224 if (getName().size() != strlen(Args.getArgString(Index)))
225 return 0;
226
227 Index += 1 + NumArgs;
228 if (Index > Args.getNumInputArgStrings())
229 return 0;
230
231 Arg *A = new Arg(getUnaliasedOption(), Index - 1 - NumArgs,
232 Args.getArgString(Index - NumArgs));
233 for (unsigned i = 1; i != NumArgs; ++i)
234 A->getValues().push_back(Args.getArgString(Index - NumArgs + i));
235 return A;
236 }
237
JoinedOrSeparateOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)238 JoinedOrSeparateOption::JoinedOrSeparateOption(OptSpecifier ID,
239 const char *Name,
240 const OptionGroup *Group,
241 const Option *Alias)
242 : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) {
243 }
244
accept(const ArgList & Args,unsigned & Index) const245 Arg *JoinedOrSeparateOption::accept(const ArgList &Args,
246 unsigned &Index) const {
247 // If this is not an exact match, it is a joined arg.
248 // FIXME: Avoid strlen.
249 if (getName().size() != strlen(Args.getArgString(Index))) {
250 const char *Value = Args.getArgString(Index) + getName().size();
251 return new Arg(this, Index++, Value);
252 }
253
254 // Otherwise it must be separate.
255 Index += 2;
256 if (Index > Args.getNumInputArgStrings())
257 return 0;
258
259 return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
260 }
261
JoinedAndSeparateOption(OptSpecifier ID,const char * Name,const OptionGroup * Group,const Option * Alias)262 JoinedAndSeparateOption::JoinedAndSeparateOption(OptSpecifier ID,
263 const char *Name,
264 const OptionGroup *Group,
265 const Option *Alias)
266 : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) {
267 }
268
accept(const ArgList & Args,unsigned & Index) const269 Arg *JoinedAndSeparateOption::accept(const ArgList &Args,
270 unsigned &Index) const {
271 // Always matches.
272
273 Index += 2;
274 if (Index > Args.getNumInputArgStrings())
275 return 0;
276
277 return new Arg(getUnaliasedOption(), Index - 2,
278 Args.getArgString(Index-2)+getName().size(),
279 Args.getArgString(Index-1));
280 }
281