cmArgumentParser: Capture keyword errors in parse results

Since commit f46b2e9142 (cmArgumentParser: Model maybe-missing string
with wrapper type, 2022-07-06) we know during parsing whether or not it
is an error for a keyword to be missing a value.  Record such errors in
the parse results structure.  Offer clients a helper method to report
them.  This provides clients with an alternative to manually checking
`keywordsMissingValue` and generating their own error message.
This commit is contained in:
Brad King
2022-07-18 16:54:13 -04:00
parent 50876f6b9a
commit b7c82b26b0
3 changed files with 55 additions and 3 deletions

View File

@@ -5,6 +5,9 @@
#include <algorithm>
#include "cmArgumentParserTypes.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
namespace ArgumentParser {
@@ -106,10 +109,27 @@ void Instance::FinishKeyword()
return;
}
if (this->ExpectValue) {
if (this->ParseResults != nullptr) {
this->ParseResults->AddKeywordError(this->Keyword,
" missing required value\n");
}
if (this->KeywordsMissingValue != nullptr) {
this->KeywordsMissingValue->emplace_back(this->Keyword);
}
}
}
bool ParseResult::MaybeReportError(cmMakefile& mf) const
{
if (*this) {
return false;
}
std::string e;
for (auto const& ke : this->KeywordErrors) {
e = cmStrCat(e, "Error after keyword \"", ke.first, "\":\n", ke.second);
}
mf.IssueMessage(MessageType::FATAL_ERROR, e);
return true;
}
} // namespace ArgumentParser

View File

@@ -6,6 +6,7 @@
#include <cassert>
#include <functional>
#include <map>
#include <string>
#include <utility>
#include <vector>
@@ -20,12 +21,29 @@
template <typename Result>
class cmArgumentParser; // IWYU pragma: keep
class cmMakefile;
namespace ArgumentParser {
class ParseResult
{
std::map<cm::string_view, std::string> KeywordErrors;
public:
explicit operator bool() const { return true; }
explicit operator bool() const { return this->KeywordErrors.empty(); }
void AddKeywordError(cm::string_view key, cm::string_view text)
{
this->KeywordErrors[key] += text;
}
std::map<cm::string_view, std::string> const& GetKeywordErrors() const
{
return this->KeywordErrors;
}
bool MaybeReportError(cmMakefile& mf) const;
};
template <typename Result>

View File

@@ -3,7 +3,9 @@
#include <initializer_list>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <cm/optional>
@@ -69,6 +71,11 @@ bool verifyResult(Result const& result,
static std::vector<cm::string_view> const missing = { "STRING_1"_s,
"LIST_1"_s,
"LIST_4"_s };
static std::map<cm::string_view, std::string> const keywordErrors = {
{ "STRING_1"_s, " missing required value\n" },
{ "LIST_1"_s, " missing required value\n" },
{ "LIST_4"_s, " missing required value\n" }
};
#define ASSERT_TRUE(x) \
do { \
@@ -78,7 +85,7 @@ bool verifyResult(Result const& result,
} \
} while (false)
ASSERT_TRUE(result);
ASSERT_TRUE(!result);
ASSERT_TRUE(result.Option1);
ASSERT_TRUE(!result.Option2);
@@ -112,6 +119,13 @@ bool verifyResult(Result const& result,
ASSERT_TRUE(unparsedArguments[0] == "bar");
ASSERT_TRUE(keywordsMissingValue == missing);
ASSERT_TRUE(result.GetKeywordErrors().size() == keywordErrors.size());
for (auto const& ke : result.GetKeywordErrors()) {
auto const ki = keywordErrors.find(ke.first);
ASSERT_TRUE(ki != keywordErrors.end());
ASSERT_TRUE(ke.second == ki->second);
}
return true;
}
@@ -179,7 +193,7 @@ bool testArgumentParserStaticBool()
std::vector<cm::string_view> keywordsMissingValue;
Result result;
ASSERT_TRUE(parserStatic.Parse(result, args, &unparsedArguments,
&keywordsMissingValue) == true);
&keywordsMissingValue) == false);
return verifyResult(result, unparsedArguments, keywordsMissingValue);
}