llvm.org GIT mirror llvm / 9dd8c0c
Option parsing: add support for alias arguments. This makes option aliases more powerful by enabling them to pass along arguments to the option they're aliasing. For example, if we have a joined option "-foo=", we can now specify a flag option "-bar" to be an alias of that, with the argument "baz". This is especially useful for the cl.exe compatible clang driver, where many options are aliases. For example, this patch enables us to alias "/Ox" to "-O3" (-O is a joined option), and "/WX" to "-Werror" (again, -W is a joined option). Differential Revision: http://llvm-reviews.chandlerc.com/D1245 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187537 91177308-0d34-0410-b5e6-96231b3b80d8 Hans Wennborg 6 years ago
7 changed file(s) with 82 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
8888 list Flags = [];
8989 OptionGroup Group = ?;
9090 Option Alias = ?;
91 list AliasArgs = [];
9192 }
9293
9394 // Helpers for defining options.
112113 // Mix-ins for adding optional attributes.
113114
114115 class Alias
116 class AliasArgs aliasargs> { list AliasArgs = aliasargs; }
115117 class EnumName { string EnumName = name; }
116118 class Flags flags> { list Flags = flags; }
117119 class Group { OptionGroup Group = group; }
4343 unsigned short Flags;
4444 unsigned short GroupID;
4545 unsigned short AliasID;
46 const char *AliasArgs;
4647 };
4748
4849 private:
102102 return Owner->getOption(Info->AliasID);
103103 }
104104
105 /// \brief Get the alias arguments as a \0 separated list.
106 /// E.g. ["foo", "bar"] would be returned as "foo\0bar\0".
107 const char *getAliasArgs() const {
108 assert(Info && "Must have a valid info!");
109 assert((!Info->AliasArgs || Info->AliasArgs[0] != 0) &&
110 "AliasArgs should be either 0 or non-empty.");
111
112 return Info->AliasArgs;
113 }
114
105115 /// \brief Get the default prefix for this option.
106116 StringRef getPrefix() const {
107117 const char *Prefix = *Info->Prefixes;
2525 // tracking, it is not an inherent limitation.
2626 assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&
2727 "Multi-level aliases are not supported.");
28
29 if (Info && getAliasArgs()) {
30 assert(getAlias().isValid() && "Only alias options can have alias args.");
31 assert(getKind() == FlagClass && "Only Flag aliases can have alias args.");
32 assert(getAlias().getKind() != FlagClass &&
33 "Cannot provide alias args to a flag option.");
34 }
2835 }
2936
3037 Option::~Option() {
105112 }
106113
107114 switch (getKind()) {
108 case FlagClass:
115 case FlagClass: {
109116 if (ArgSize != strlen(Args.getArgString(Index)))
110117 return 0;
111118
112 return new Arg(UnaliasedOption, Spelling, Index++);
119 Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
120 if (getAliasArgs()) {
121 const char *Val = getAliasArgs();
122 while (*Val != '\0') {
123 A->getValues().push_back(Val);
124
125 // Move past the '\0' to the next argument.
126 Val += strlen(Val) + 1;
127 }
128 }
129 return A;
130 }
113131 case JoinedClass: {
114132 const char *Value = Args.getArgString(Index) + ArgSize;
115133 return new Arg(UnaliasedOption, Spelling, Index++, Value);
1616 using namespace llvm;
1717 using namespace llvm::opt;
1818
19 #define SUPPORT_ALIASARGS // FIXME: Remove when no longer necessary.
20
1921 enum ID {
2022 OPT_INVALID = 0, // This is not an option ID.
21 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
23 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
2224 HELPTEXT, METAVAR) OPT_##ID,
2325 #include "Opts.inc"
2426 LastOption
3638 };
3739
3840 static const OptTable::Info InfoTable[] = {
39 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
41 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
4042 HELPTEXT, METAVAR) \
4143 { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
42 FLAGS, OPT_##GROUP, OPT_##ALIAS },
44 FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
4345 #include "Opts.inc"
4446 #undef OPTION
4547 };
144146 OwningPtr AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC));
145147 EXPECT_TRUE(AL->hasArg(OPT_H));
146148 }
149
150 TEST(Option, AliasArgs) {
151 TestOptTable T;
152 unsigned MAI, MAC;
153
154 const char *MyArgs[] = { "-J", "-Joo" };
155 OwningPtr AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC));
156 EXPECT_TRUE(AL->hasArg(OPT_B));
157 EXPECT_EQ(AL->getAllArgValues(OPT_B)[0], "foo");
158 EXPECT_EQ(AL->getAllArgValues(OPT_B)[1], "bar");
159 }
1818
1919 def my_group : OptionGroup<"my group">;
2020 def I : Flag<["-"], "I">, Alias, Group;
21
22 def J : Flag<["-"], "J">, Alias, AliasArgs<["foo"]>;
23 def Joo : Flag<["-"], "Joo">, Alias, AliasArgs<["bar"]>;
151151 OS << "/////////\n";
152152 OS << "// Groups\n\n";
153153 OS << "#ifdef OPTION\n";
154
155 // FIXME: Remove when option parsing clients are updated.
156 OS << "#ifdef SUPPORT_ALIASARGS\n";
157 OS << "#define OPTIONX OPTION\n";
158 OS << "#else\n";
159 OS << "#define OPTIONX(prefix, name, id, kind, group, alias, aliasargs, "
160 << "flags, param, helptext, metavar) "
161 << "OPTION(prefix, name, id, kind, "
162 << "group, alias, flags, param, helptext, metavar)\n";
163 OS << "#endif\n";
164
154165 for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
155166 const Record &R = *Groups[i];
156167
157168 // Start a single option entry.
158 OS << "OPTION(";
169 OS << "OPTIONX(";
159170
160171 // The option prefix;
161172 OS << "0";
177188 OS << "INVALID";
178189
179190 // The other option arguments (unused for groups).
180 OS << ", INVALID, 0, 0";
191 OS << ", INVALID, 0, 0, 0";
181192
182193 // The option help text.
183194 if (!isa(R.getValueInit("HelpText"))) {
198209 const Record &R = *Opts[i];
199210
200211 // Start a single option entry.
201 OS << "OPTION(";
212 OS << "OPTIONX(";
202213
203214 // The option prefix;
204215 std::vector prf = R.getValueAsListOfStrings("Prefixes");
226237 OS << getOptionName(*DI->getDef());
227238 else
228239 OS << "INVALID";
240
241 // The option alias arguments (if any).
242 // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
243 // would become "foo\0bar\0". Note that the compiler adds an implicit
244 // terminating \0 at the end.
245 OS << ", ";
246 std::vector AliasArgs = R.getValueAsListOfStrings("AliasArgs");
247 if (AliasArgs.size() == 0) {
248 OS << "0";
249 } else {
250 OS << "\"";
251 for (size_t i = 0, e = AliasArgs.size(); i != e; ++i)
252 OS << AliasArgs[i] << "\\0";
253 OS << "\"";
254 }
229255
230256 // The option flags.
231257 const ListInit *LI = R.getValueAsListInit("Flags");
260286
261287 OS << ")\n";
262288 }
289 OS << "#undef OPTIONX\n"; // FIXME: Remove when option clients are updated.
263290 OS << "#endif\n";
264291 }
265292 } // end namespace llvm