瀏覽代碼

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.
Brad King 3 年之前
父節點
當前提交
b7c82b26b0
共有 3 個文件被更改,包括 55 次插入3 次删除
  1. 20 0
      Source/cmArgumentParser.cxx
  2. 19 1
      Source/cmArgumentParser.h
  3. 16 2
      Tests/CMakeLib/testArgumentParser.cxx

+ 20 - 0
Source/cmArgumentParser.cxx

@@ -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

+ 19 - 1
Source/cmArgumentParser.h

@@ -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>

+ 16 - 2
Tests/CMakeLib/testArgumentParser.cxx

@@ -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);
 }