diff --git a/include/llvm/Support/YAMLParser.h b/include/llvm/Support/YAMLParser.h index 44daf785090..7baf69eebac 100644 --- a/include/llvm/Support/YAMLParser.h +++ b/include/llvm/Support/YAMLParser.h @@ -40,6 +40,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" #include #include #include @@ -51,7 +52,6 @@ namespace llvm { class MemoryBufferRef; -class SourceMgr; class raw_ostream; class Twine; @@ -100,7 +100,8 @@ public: return !failed(); } - void printError(Node *N, const Twine &Msg); + void printError(Node *N, const Twine &Msg, + SourceMgr::DiagKind Kind = SourceMgr::DK_Error); private: friend class Document; diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index acb1d61cf56..f32a6ca92d2 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -789,6 +789,7 @@ public: virtual NodeKind getNodeKind() = 0; virtual void setError(const Twine &) = 0; + virtual void setAllowUnknownKeys(bool Allow); template void enumCase(T &Val, const char* Str, const T ConstVal) { @@ -1495,6 +1496,9 @@ private: void setError(HNode *hnode, const Twine &message); void setError(Node *node, const Twine &message); + void reportWarning(HNode *hnode, const Twine &message); + void reportWarning(Node *hnode, const Twine &message); + public: // These are only used by operator>>. They could be private // if those templated things could be made friends. @@ -1504,6 +1508,8 @@ public: /// Returns the current node that's being parsed by the YAML Parser. const Node *getCurrentNode() const; + void setAllowUnknownKeys(bool Allow) override; + private: SourceMgr SrcMgr; // must be before Strm std::unique_ptr Strm; @@ -1514,6 +1520,7 @@ private: std::vector BitValuesUsed; HNode *CurrentNode = nullptr; bool ScalarMatchFound = false; + bool AllowUnknownKeys = false; }; /// diff --git a/lib/Support/YAMLParser.cpp b/lib/Support/YAMLParser.cpp index ca8ffdc47af..b9bbdc33a43 100644 --- a/lib/Support/YAMLParser.cpp +++ b/lib/Support/YAMLParser.cpp @@ -1775,12 +1775,9 @@ Stream::~Stream() = default; bool Stream::failed() { return scanner->failed(); } -void Stream::printError(Node *N, const Twine &Msg) { +void Stream::printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind) { SMRange Range = N ? N->getSourceRange() : SMRange(); - scanner->printError( Range.Start - , SourceMgr::DK_Error - , Msg - , Range); + scanner->printError(Range.Start, Kind, Msg, Range); } document_iterator Stream::begin() { diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index 9ac7c65e19f..8a5bb653d7a 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -48,6 +48,10 @@ void IO::setContext(void *Context) { Ctxt = Context; } +void IO::setAllowUnknownKeys(bool Allow) { + llvm_unreachable("Only supported for Input"); +} + //===----------------------------------------------------------------------===// // Input //===----------------------------------------------------------------------===// @@ -197,8 +201,12 @@ void Input::endMapping() { return; for (const auto &NN : MN->Mapping) { if (!is_contained(MN->ValidKeys, NN.first())) { - setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'"); - break; + HNode *ReportNode = NN.second.get(); + if (!AllowUnknownKeys) { + setError(ReportNode, Twine("unknown key '") + NN.first() + "'"); + break; + } else + reportWarning(ReportNode, Twine("unknown key '") + NN.first() + "'"); } } } @@ -370,6 +378,11 @@ void Input::setError(Node *node, const Twine &message) { EC = make_error_code(errc::invalid_argument); } +void Input::reportWarning(HNode *hnode, const Twine &message) { + assert(hnode && "HNode must not be NULL"); + Strm->printError(hnode->_node, message, SourceMgr::DK_Warning); +} + std::unique_ptr Input::createHNodes(Node *N) { SmallString<128> StringStorage; if (ScalarNode *SN = dyn_cast(N)) { @@ -428,6 +441,8 @@ void Input::setError(const Twine &Message) { setError(CurrentNode, Message); } +void Input::setAllowUnknownKeys(bool Allow) { AllowUnknownKeys = Allow; } + bool Input::canElideEmptySequence() { return false; } diff --git a/unittests/ObjectYAML/YAMLTest.cpp b/unittests/ObjectYAML/YAMLTest.cpp index 3d283a03b22..53582a98721 100644 --- a/unittests/ObjectYAML/YAMLTest.cpp +++ b/unittests/ObjectYAML/YAMLTest.cpp @@ -35,3 +35,21 @@ TEST(ObjectYAML, BinaryRef) { YOut << BH; EXPECT_NE(OS.str().find("''"), StringRef::npos); } + +TEST(ObjectYAML, UnknownOption) { + StringRef InputYAML = "InvalidKey: InvalidValue\n" + "Binary: AAAA\n"; + BinaryHolder BH; + yaml::Input Input(InputYAML); + // test 1: default in trying to parse invalid key is an error case. + Input >> BH; + EXPECT_EQ(Input.error().value(), 22); + + // test 2: only warn about invalid key if actively set. + yaml::Input Input2(InputYAML); + BinaryHolder BH2; + Input2.setAllowUnknownKeys(true); + Input2 >> BH2; + EXPECT_EQ(BH2.Binary, yaml::BinaryRef("AAAA")); + EXPECT_EQ(Input2.error().value(), 0); +}