From: Nick Kledzik Date: Thu, 21 Nov 2013 00:28:07 +0000 (+0000) Subject: YAML I/O add support for validate() X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7cd45f29b26b6cb4e0019b7355ed69db9ab55992;p=platform%2Fupstream%2Fllvm.git YAML I/O add support for validate() MappingTrait template specializations can now have a validate() method which performs semantic checking. For details, see . llvm-svn: 195286 --- diff --git a/llvm/docs/YamlIO.rst b/llvm/docs/YamlIO.rst index 5ec0a01..46609a3 100644 --- a/llvm/docs/YamlIO.rst +++ b/llvm/docs/YamlIO.rst @@ -647,6 +647,44 @@ mappings, as long as they are convertable. To check a tag, inside your mapping() method you can use io.mapTag() to specify what the tag should be. This will also add that tag when writing yaml. +Validation +---------- + +Sometimes in a yaml map, each key/value pair is valid, but the combination is +not. This is similar to something having no syntax errors, but still having +semantic errors. To support semantic level checking, YAML I/O allows +an optional ``validate()`` method in a MappingTraits template specialization. + +When parsing yaml, the ``validate()`` method is call *after* all key/values in +the map have been processed. Any error message returned by the ``validate()`` +method during input will be printed just a like a syntax error would be printed. +When writing yaml, the ``validate()`` method is called *before* the yaml +key/values are written. Any error during output will trigger an ``assert()`` +because it is a programming error to have invalid struct values. + + +.. code-block:: c++ + + using llvm::yaml::MappingTraits; + using llvm::yaml::IO; + + struct Stuff { + ... + }; + + template <> + struct MappingTraits { + static void mapping(IO &io, Stuff &stuff) { + ... + } + static StringRef validate(IO &io, Stuff &stuff) { + // Look at all fields in 'stuff' and if there + // are any bad values return a string describing + // the error. Otherwise return an empty string. + return StringRef(); + } + }; + Sequence ======== diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index 27c1393..1716a9d 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -44,6 +44,8 @@ template struct MappingTraits { // Must provide: // static void mapping(IO &io, T &fields); + // Optionally may provide: + // static StringRef validate(IO &io, T &fields); }; @@ -226,6 +228,23 @@ public: static bool const value = (sizeof(test >(0)) == 1); }; +// Test if MappingTraits::validate() is defined on type T. +template +struct has_MappingValidateTraits +{ + typedef StringRef (*Signature_validate)(class IO&, T&); + + template + static char test(SameType*); + + template + static double test(...); + +public: + static bool const value = (sizeof(test >(0)) == 1); +}; + + // Test if SequenceTraits is defined on type T. template @@ -309,7 +328,15 @@ struct missingTraits : public llvm::integral_constant::value && !has_DocumentListTraits::value > {}; +template +struct validatedMappingTraits : public llvm::integral_constant::value + && has_MappingValidateTraits::value> {}; +template +struct unvalidatedMappingTraits : public llvm::integral_constant::value + && !has_MappingValidateTraits::value> {}; // Base class for Input and Output. class IO { public: @@ -483,7 +510,27 @@ yamlize(IO &io, T &Val, bool) { template -typename llvm::enable_if_c::value, void>::type +typename llvm::enable_if_c::value, void>::type +yamlize(IO &io, T &Val, bool) { + io.beginMapping(); + if (io.outputting()) { + StringRef Err = MappingTraits::validate(io, Val); + if (!Err.empty()) { + llvm::errs() << Err << "\n"; + assert(Err.empty() && "invalid struct trying to be written as yaml"); + } + } + MappingTraits::mapping(io, Val); + if (!io.outputting()) { + StringRef Err = MappingTraits::validate(io, Val); + if (!Err.empty()) + io.setError(Err); + } + io.endMapping(); +} + +template +typename llvm::enable_if_c::value, void>::type yamlize(IO &io, T &Val, bool) { io.beginMapping(); MappingTraits::mapping(io, Val); diff --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp index 07d7045..52a8f6b 100644 --- a/llvm/unittests/Support/YAMLIOTest.cpp +++ b/llvm/unittests/Support/YAMLIOTest.cpp @@ -27,6 +27,13 @@ using llvm::yaml::Hex32; using llvm::yaml::Hex64; + + +static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) { +} + + + //===----------------------------------------------------------------------===// // Test MappingTraits //===----------------------------------------------------------------------===// @@ -1115,18 +1122,51 @@ TEST(YAMLIO, TestTaggedDocumentsWriteAndRead) { } - //===----------------------------------------------------------------------===// -// Test error handling +// Test mapping validation //===----------------------------------------------------------------------===// +struct MyValidation { + double value; +}; +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyValidation) -static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) { +namespace llvm { +namespace yaml { + template <> + struct MappingTraits { + static void mapping(IO &io, MyValidation &d) { + io.mapRequired("value", d.value); + } + static StringRef validate(IO &io, MyValidation &d) { + if (d.value < 0) + return "negative value"; + return StringRef(); + } + }; + } } // +// Test that validate() is called and complains about the negative value. +// +TEST(YAMLIO, TestValidatingInput) { + std::vector docList; + Input yin("--- \nvalue: 3.0\n" + "--- \nvalue: -1.0\n...\n", + NULL, suppressErrorMessages); + yin >> docList; + EXPECT_TRUE(yin.error()); +} + + +//===----------------------------------------------------------------------===// +// Test error handling +//===----------------------------------------------------------------------===// + +// // Test error handling of unknown enumerated scalar // TEST(YAMLIO, TestColorsReadError) {