Skip to content

Commit 405e836

Browse files
committed
[CommandLine] Add inline ArgName printing
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
1 parent 9f97480 commit 405e836

File tree

2 files changed

+70
-14
lines changed

2 files changed

+70
-14
lines changed

llvm/lib/Support/CommandLine.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,26 @@ void parser<char>::anchor() {}
8888

8989
//===----------------------------------------------------------------------===//
9090

91-
static StringRef ArgPrefix = " -";
92-
static StringRef ArgPrefixLong = " --";
91+
const static size_t DefaultPad = 2;
92+
93+
static StringRef ArgPrefix = "-";
94+
static StringRef ArgPrefixLong = "--";
9395
static StringRef ArgHelpPrefix = " - ";
9496

95-
static size_t argPlusPrefixesSize(StringRef ArgName) {
97+
static size_t argPlusPrefixesSize(StringRef ArgName, size_t Pad = DefaultPad) {
9698
size_t Len = ArgName.size();
9799
if (Len == 1)
98-
return Len + ArgPrefix.size() + ArgHelpPrefix.size();
99-
return Len + ArgPrefixLong.size() + ArgHelpPrefix.size();
100+
return Len + Pad + ArgPrefix.size() + ArgHelpPrefix.size();
101+
return Len + Pad + ArgPrefixLong.size() + ArgHelpPrefix.size();
100102
}
101103

102-
static StringRef argPrefix(StringRef ArgName) {
103-
if (ArgName.size() == 1)
104-
return ArgPrefix;
105-
return ArgPrefixLong;
104+
static SmallString<8> argPrefix(StringRef ArgName, size_t Pad = DefaultPad) {
105+
SmallString<8> Prefix;
106+
for (size_t I = 0; I < Pad; ++I) {
107+
Prefix.push_back(' ');
108+
}
109+
Prefix.append(ArgName.size() > 1 ? ArgPrefixLong : ArgPrefix);
110+
return Prefix;
106111
}
107112

108113
// Option predicates...
@@ -119,13 +124,14 @@ namespace {
119124

120125
class PrintArg {
121126
StringRef ArgName;
127+
size_t Pad;
122128
public:
123-
PrintArg(StringRef ArgName) : ArgName(ArgName) {}
124-
friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&);
129+
PrintArg(StringRef ArgName, size_t Pad = DefaultPad) : ArgName(ArgName), Pad(Pad) {}
130+
friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg &);
125131
};
126132

127133
raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) {
128-
OS << argPrefix(Arg.ArgName) << Arg.ArgName;
134+
OS << argPrefix(Arg.ArgName, Arg.Pad) << Arg.ArgName;
129135
return OS;
130136
}
131137

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

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

16061612
Errs << " option: " << Message << "\n";
16071613
return true;

llvm/unittests/Support/CommandLineTest.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,4 +1653,54 @@ TEST(CommandLineTest, LongOptions) {
16531653
EXPECT_TRUE(Errs.empty()); Errs.clear();
16541654
cl::ResetAllOptionOccurrences();
16551655
}
1656+
1657+
TEST(CommandLineTest, OptionErrorMessage) {
1658+
// When there is an error, we expect some error message like:
1659+
// prog: for the -a option: [...]
1660+
//
1661+
// Test whether the "for the -a option"-part is correctly formatted.
1662+
cl::ResetCommandLineParser();
1663+
1664+
StackOption<bool> OptA("a", cl::desc("Some option"));
1665+
StackOption<bool> OptLong("long", cl::desc("Some long option"));
1666+
1667+
std::string Errs;
1668+
raw_string_ostream OS(Errs);
1669+
1670+
OptA.error("custom error", OS);
1671+
OS.flush();
1672+
EXPECT_FALSE(Errs.find("for the -a option:") == std::string::npos);
1673+
Errs.clear();
1674+
1675+
OptLong.error("custom error", OS);
1676+
OS.flush();
1677+
EXPECT_FALSE(Errs.find("for the --long option:") == std::string::npos);
1678+
Errs.clear();
1679+
1680+
cl::ResetAllOptionOccurrences();
1681+
}
1682+
1683+
TEST(CommandLineTest, OptionErrorMessageSuggest) {
1684+
// When there is an error, and the edit-distance is not very large,
1685+
// we expect some error message like:
1686+
// prog: did you mean '--option'?
1687+
//
1688+
// Test whether this message is well-formatted.
1689+
cl::ResetCommandLineParser();
1690+
1691+
StackOption<bool> OptLong("aluminium", cl::desc("Some long option"));
1692+
1693+
const char *args[] = {"prog", "--aluminum"};
1694+
1695+
std::string Errs;
1696+
raw_string_ostream OS(Errs);
1697+
1698+
EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS));
1699+
OS.flush();
1700+
EXPECT_FALSE(Errs.find("prog: Did you mean '--aluminium'?\n") ==
1701+
std::string::npos);
1702+
Errs.clear();
1703+
1704+
cl::ResetAllOptionOccurrences();
1705+
}
16561706
} // anonymous namespace

0 commit comments

Comments
 (0)