mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[CommandLine] Error message for incorrect PositionalEatArgs usage
Summary: bugpoint has several options specified as `PositionalEatArgs` to pass options through to the underlying tool, e.g. `-tool-args`. The `-help` message suggests the usage is: `-tool-args=<string>`. However, this is misleading, because that's not how these arguments work. Rather than taking a value, the option consumes all positional arguments until the next recognized option (or all arguments if `--` is specified at some point). To make this slightly clearer, instead print the help as: ``` -tool-args <string>... - <tool arguments>... ``` Additionally, add an error if the user attempts to use a `PositionalEatArgs` argument with a value, instead of silently ignoring it. Example: ``` ./bin/bugpoint -tool-args=-mpcu=skylake-avx512 bugpoint: for the -tool-args option: This argument does not take a value. Instead, it consumes any positional arguments until the next recognized option. ``` Reviewed By: aprantl Differential Revision: https://reviews.llvm.org/D46787 llvm-svn: 332311
This commit is contained in:
parent
aa4e57f5b7
commit
49d76cdb55
@ -30,6 +30,7 @@
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
@ -362,7 +363,10 @@ public:
|
||||
bool MultiArg = false);
|
||||
|
||||
// Prints option name followed by message. Always returns true.
|
||||
bool error(const Twine &Message, StringRef ArgName = StringRef());
|
||||
bool error(const Twine &Message, StringRef ArgName = StringRef(), raw_ostream &Errs = llvm::errs());
|
||||
bool error(const Twine &Message, raw_ostream &Errs) {
|
||||
return error(Message, StringRef(), Errs);
|
||||
}
|
||||
|
||||
inline int getNumOccurrences() const { return NumOccurrences; }
|
||||
inline void reset() { NumOccurrences = 0; }
|
||||
|
@ -1270,8 +1270,15 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
|
||||
|
||||
// If this is a named positional argument, just remember that it is the
|
||||
// active one...
|
||||
if (Handler->getFormattingFlag() == cl::Positional)
|
||||
if (Handler->getFormattingFlag() == cl::Positional) {
|
||||
if ((Handler->getMiscFlags() & PositionalEatsArgs) && !Value.empty()) {
|
||||
Handler->error("This argument does not take a value.\n"
|
||||
"\tInstead, it consumes any positional arguments until "
|
||||
"the next recognized option.", *Errs);
|
||||
ErrorParsing = true;
|
||||
}
|
||||
ActivePositionalArg = Handler;
|
||||
}
|
||||
else
|
||||
ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i);
|
||||
}
|
||||
@ -1396,15 +1403,15 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
|
||||
// Option Base class implementation
|
||||
//
|
||||
|
||||
bool Option::error(const Twine &Message, StringRef ArgName) {
|
||||
bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) {
|
||||
if (!ArgName.data())
|
||||
ArgName = ArgStr;
|
||||
if (ArgName.empty())
|
||||
errs() << HelpStr; // Be nice for positional arguments
|
||||
Errs << HelpStr; // Be nice for positional arguments
|
||||
else
|
||||
errs() << GlobalParser->ProgramName << ": for the -" << ArgName;
|
||||
Errs << GlobalParser->ProgramName << ": for the -" << ArgName;
|
||||
|
||||
errs() << " option: " << Message << "\n";
|
||||
Errs << " option: " << Message << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1474,8 +1481,12 @@ void alias::printOptionInfo(size_t GlobalWidth) const {
|
||||
size_t basic_parser_impl::getOptionWidth(const Option &O) const {
|
||||
size_t Len = O.ArgStr.size();
|
||||
auto ValName = getValueName();
|
||||
if (!ValName.empty())
|
||||
Len += getValueStr(O, ValName).size() + 3;
|
||||
if (!ValName.empty()) {
|
||||
size_t FormattingLen = 3;
|
||||
if (O.getMiscFlags() & PositionalEatsArgs)
|
||||
FormattingLen = 6;
|
||||
Len += getValueStr(O, ValName).size() + FormattingLen;
|
||||
}
|
||||
|
||||
return Len + 6;
|
||||
}
|
||||
@ -1488,8 +1499,13 @@ void basic_parser_impl::printOptionInfo(const Option &O,
|
||||
outs() << " -" << O.ArgStr;
|
||||
|
||||
auto ValName = getValueName();
|
||||
if (!ValName.empty())
|
||||
outs() << "=<" << getValueStr(O, ValName) << '>';
|
||||
if (!ValName.empty()) {
|
||||
if (O.getMiscFlags() & PositionalEatsArgs) {
|
||||
outs() << " <" << getValueStr(O, ValName) << ">...";
|
||||
} else {
|
||||
outs() << "=<" << getValueStr(O, ValName) << '>';
|
||||
}
|
||||
}
|
||||
|
||||
Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
|
||||
}
|
||||
|
@ -816,4 +816,23 @@ TEST(CommandLineTest, ReadConfigFile) {
|
||||
llvm::sys::fs::remove(TestDir);
|
||||
}
|
||||
|
||||
TEST(CommandLineTest, PositionalEatArgsError) {
|
||||
static cl::list<std::string> PosEatArgs("positional-eat-args", cl::Positional,
|
||||
cl::desc("<arguments>..."), cl::ZeroOrMore,
|
||||
cl::PositionalEatsArgs);
|
||||
|
||||
const char *args[] = {"prog", "-positional-eat-args=XXXX"};
|
||||
const char *args2[] = {"prog", "-positional-eat-args=XXXX", "-foo"};
|
||||
const char *args3[] = {"prog", "-positional-eat-args", "-foo"};
|
||||
|
||||
std::string Errs;
|
||||
raw_string_ostream OS(Errs);
|
||||
EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); OS.flush();
|
||||
EXPECT_FALSE(Errs.empty()); Errs.clear();
|
||||
EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); OS.flush();
|
||||
EXPECT_FALSE(Errs.empty()); Errs.clear();
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); OS.flush();
|
||||
EXPECT_TRUE(Errs.empty());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user