[llvm] r195286 - YAML I/O add support for validate()

Nick Kledzik kledzik at apple.com
Wed Nov 20 16:28:07 PST 2013


Author: kledzik
Date: Wed Nov 20 18:28:07 2013
New Revision: 195286

URL: http://llvm.org/viewvc/llvm-project?rev=195286&view=rev
Log:
YAML I/O add support for validate()

MappingTrait template specializations can now have a validate() method which 
performs semantic checking. For details, see <http://llvm.org/docs/YamlIO.html>.


Modified:
    llvm/trunk/docs/YamlIO.rst
    llvm/trunk/include/llvm/Support/YAMLTraits.h
    llvm/trunk/unittests/Support/YAMLIOTest.cpp

Modified: llvm/trunk/docs/YamlIO.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/YamlIO.rst?rev=195286&r1=195285&r2=195286&view=diff
==============================================================================
--- llvm/trunk/docs/YamlIO.rst (original)
+++ llvm/trunk/docs/YamlIO.rst Wed Nov 20 18:28:07 2013
@@ -647,6 +647,44 @@ mappings, as long as they are convertabl
 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<Stuff> {
+      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
 ========

Modified: llvm/trunk/include/llvm/Support/YAMLTraits.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/YAMLTraits.h?rev=195286&r1=195285&r2=195286&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/YAMLTraits.h (original)
+++ llvm/trunk/include/llvm/Support/YAMLTraits.h Wed Nov 20 18:28:07 2013
@@ -44,6 +44,8 @@ template<class T>
 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<MappingTraits<T> >(0)) == 1);
 };
 
+// Test if MappingTraits<T>::validate() is defined on type T.
+template <class T>
+struct has_MappingValidateTraits
+{
+  typedef StringRef (*Signature_validate)(class IO&, T&);
+
+  template <typename U>
+  static char test(SameType<Signature_validate, &U::validate>*);
+
+  template <typename U>
+  static double test(...);
+
+public:
+  static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
+};
+
+
 
 // Test if SequenceTraits<T> is defined on type T.
 template <class T>
@@ -309,7 +328,15 @@ struct missingTraits : public  llvm::int
                                       && !has_SequenceTraits<T>::value
                                       && !has_DocumentListTraits<T>::value >  {};
 
+template<typename T>
+struct validatedMappingTraits : public  llvm::integral_constant<bool,
+                                       has_MappingTraits<T>::value
+                                    && has_MappingValidateTraits<T>::value> {};
 
+template<typename T>
+struct unvalidatedMappingTraits : public  llvm::integral_constant<bool,
+                                        has_MappingTraits<T>::value
+                                    && !has_MappingValidateTraits<T>::value> {};
 // Base class for Input and Output.
 class IO {
 public:
@@ -483,7 +510,27 @@ yamlize(IO &io, T &Val, bool) {
 
 
 template<typename T>
-typename llvm::enable_if_c<has_MappingTraits<T>::value, void>::type
+typename llvm::enable_if_c<validatedMappingTraits<T>::value, void>::type
+yamlize(IO &io, T &Val, bool) {
+  io.beginMapping();
+  if (io.outputting()) {
+    StringRef Err = MappingTraits<T>::validate(io, Val);
+    if (!Err.empty()) {
+      llvm::errs() << Err << "\n";
+      assert(Err.empty() && "invalid struct trying to be written as yaml");
+    }
+  }
+  MappingTraits<T>::mapping(io, Val);
+  if (!io.outputting()) {
+    StringRef Err = MappingTraits<T>::validate(io, Val);
+    if (!Err.empty())
+      io.setError(Err);
+  }
+  io.endMapping();
+}
+
+template<typename T>
+typename llvm::enable_if_c<unvalidatedMappingTraits<T>::value, void>::type
 yamlize(IO &io, T &Val, bool) {
   io.beginMapping();
   MappingTraits<T>::mapping(io, Val);

Modified: llvm/trunk/unittests/Support/YAMLIOTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/YAMLIOTest.cpp?rev=195286&r1=195285&r2=195286&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/YAMLIOTest.cpp (original)
+++ llvm/trunk/unittests/Support/YAMLIOTest.cpp Wed Nov 20 18:28:07 2013
@@ -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, TestTaggedDocumentsWriteAnd
 }
 
 
-
 //===----------------------------------------------------------------------===//
-//  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<MyValidation> {
+    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<MyValidation> 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) {





More information about the llvm-commits mailing list