Skip to content

Commit

Permalink
[CommandLine] Add inline ArgName printing
Browse files Browse the repository at this point in the history
Summary:
This patch adds PrintArgInline (after PrintArg) that strips the
leading spaces from an argument before printing them, for usage
inline.

Related bug: PR42943 <https://bugs.llvm.org/show_bug.cgi?id=42943>

Patch by Daan Sprenkels!

Reviewers: jhenderson, chandlerc, hintonda

Reviewed By: jhenderson

Subscribers: hiraditya, kristina, llvm-commits, dsprenkels

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D69501
  • Loading branch information
donhinton committed Nov 6, 2019
1 parent 9f97480 commit 405e836
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 14 deletions.
34 changes: 20 additions & 14 deletions llvm/lib/Support/CommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,26 @@ void parser<char>::anchor() {}

//===----------------------------------------------------------------------===//

static StringRef ArgPrefix = " -";
static StringRef ArgPrefixLong = " --";
const static size_t DefaultPad = 2;

static StringRef ArgPrefix = "-";
static StringRef ArgPrefixLong = "--";
static StringRef ArgHelpPrefix = " - ";

static size_t argPlusPrefixesSize(StringRef ArgName) {
static size_t argPlusPrefixesSize(StringRef ArgName, size_t Pad = DefaultPad) {
size_t Len = ArgName.size();
if (Len == 1)
return Len + ArgPrefix.size() + ArgHelpPrefix.size();
return Len + ArgPrefixLong.size() + ArgHelpPrefix.size();
return Len + Pad + ArgPrefix.size() + ArgHelpPrefix.size();
return Len + Pad + ArgPrefixLong.size() + ArgHelpPrefix.size();
}

static StringRef argPrefix(StringRef ArgName) {
if (ArgName.size() == 1)
return ArgPrefix;
return ArgPrefixLong;
static SmallString<8> argPrefix(StringRef ArgName, size_t Pad = DefaultPad) {
SmallString<8> Prefix;
for (size_t I = 0; I < Pad; ++I) {
Prefix.push_back(' ');
}
Prefix.append(ArgName.size() > 1 ? ArgPrefixLong : ArgPrefix);
return Prefix;
}

// Option predicates...
Expand All @@ -119,13 +124,14 @@ namespace {

class PrintArg {
StringRef ArgName;
size_t Pad;
public:
PrintArg(StringRef ArgName) : ArgName(ArgName) {}
friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&);
PrintArg(StringRef ArgName, size_t Pad = DefaultPad) : ArgName(ArgName), Pad(Pad) {}
friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg &);
};

raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) {
OS << argPrefix(Arg.ArgName) << Arg.ArgName;
OS << argPrefix(Arg.ArgName, Arg.Pad) << Arg.ArgName;
return OS;
}

Expand Down Expand Up @@ -1447,7 +1453,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
if (NearestHandler) {
// If we know a near match, report it as well.
*Errs << ProgramName << ": Did you mean '"
<< PrintArg(NearestHandlerString) << "'?\n";
<< PrintArg(NearestHandlerString, 0) << "'?\n";
}

ErrorParsing = true;
Expand Down Expand Up @@ -1601,7 +1607,7 @@ bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) {
if (ArgName.empty())
Errs << HelpStr; // Be nice for positional arguments
else
Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName);
Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName, 0);

Errs << " option: " << Message << "\n";
return true;
Expand Down
50 changes: 50 additions & 0 deletions llvm/unittests/Support/CommandLineTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1653,4 +1653,54 @@ TEST(CommandLineTest, LongOptions) {
EXPECT_TRUE(Errs.empty()); Errs.clear();
cl::ResetAllOptionOccurrences();
}

TEST(CommandLineTest, OptionErrorMessage) {
// When there is an error, we expect some error message like:
// prog: for the -a option: [...]
//
// Test whether the "for the -a option"-part is correctly formatted.
cl::ResetCommandLineParser();

StackOption<bool> OptA("a", cl::desc("Some option"));
StackOption<bool> OptLong("long", cl::desc("Some long option"));

std::string Errs;
raw_string_ostream OS(Errs);

OptA.error("custom error", OS);
OS.flush();
EXPECT_FALSE(Errs.find("for the -a option:") == std::string::npos);
Errs.clear();

OptLong.error("custom error", OS);
OS.flush();
EXPECT_FALSE(Errs.find("for the --long option:") == std::string::npos);
Errs.clear();

cl::ResetAllOptionOccurrences();
}

TEST(CommandLineTest, OptionErrorMessageSuggest) {
// When there is an error, and the edit-distance is not very large,
// we expect some error message like:
// prog: did you mean '--option'?
//
// Test whether this message is well-formatted.
cl::ResetCommandLineParser();

StackOption<bool> OptLong("aluminium", cl::desc("Some long option"));

const char *args[] = {"prog", "--aluminum"};

std::string Errs;
raw_string_ostream OS(Errs);

EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
OS.flush();
EXPECT_FALSE(Errs.find("prog: Did you mean '--aluminium'?\n") ==
std::string::npos);
Errs.clear();

cl::ResetAllOptionOccurrences();
}
} // anonymous namespace

0 comments on commit 405e836

Please sign in to comment.