[llvm] r333527 - [YAML] Quote multiline string scalars

Ilya Biryukov via llvm-commits llvm-commits at lists.llvm.org
Wed May 30 03:40:11 PDT 2018


Author: ibiryukov
Date: Wed May 30 03:40:11 2018
New Revision: 333527

URL: http://llvm.org/viewvc/llvm-project?rev=333527&view=rev
Log:
[YAML] Quote multiline string scalars

Summary:
Otherwise, the YAML parser breaks when trying to read them back in
'key: multiline_string_value' cases.

This patch fixes a problem when serializing structs which contain multi-line strings.
E.g., if we try to serialize  the following struct
```
{ "key1": "first line\nsecond line",
  "key2": "another string" }`
```

Before this patch, we got the YAML output that failed to parse:
```
key1: first line
second line
key2: another string
```

After the patch, we get:
```
key1: 'first line
second line'
key2: another string
```

Reviewers: sammccall

Reviewed By: sammccall

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D47468

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

Modified: llvm/trunk/include/llvm/Support/YAMLTraits.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/YAMLTraits.h?rev=333527&r1=333526&r2=333527&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/YAMLTraits.h (original)
+++ llvm/trunk/include/llvm/Support/YAMLTraits.h Wed May 30 03:40:11 2018
@@ -540,11 +540,14 @@ inline QuotingType needsQuotes(StringRef
     case '.':
     case ',':
     case ' ':
-    // TAB (0x9), LF (0xA), CR (0xD) and NEL (0x85) are allowed.
+    // TAB (0x9) is allowed in unquoted strings.
     case 0x9:
+      continue;
+    // LF(0xA) and CR(0xD) may delimit values and so require at least single
+    // quotes.
     case 0xA:
     case 0xD:
-    case 0x85:
+      MaxQuotingNeeded = QuotingType::Single;
       continue;
     // DEL (0x7F) are excluded from the allowed character range.
     case 0x7F:

Modified: llvm/trunk/unittests/Support/YAMLIOTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/YAMLIOTest.cpp?rev=333527&r1=333526&r2=333527&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/YAMLIOTest.cpp (original)
+++ llvm/trunk/unittests/Support/YAMLIOTest.cpp Wed May 30 03:40:11 2018
@@ -13,6 +13,7 @@
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 using llvm::yaml::Input;
@@ -25,6 +26,7 @@ using llvm::yaml::Hex8;
 using llvm::yaml::Hex16;
 using llvm::yaml::Hex32;
 using llvm::yaml::Hex64;
+using ::testing::StartsWith;
 
 
 
@@ -249,6 +251,72 @@ TEST(YAMLIO, TestGivenFilename) {
   EXPECT_TRUE(!!yin.error());
 }
 
+struct WithStringField {
+  std::string str1;
+  std::string str2;
+  std::string str3;
+};
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<WithStringField> {
+  static void mapping(IO &io, WithStringField &fb) {
+    io.mapRequired("str1", fb.str1);
+    io.mapRequired("str2", fb.str2);
+    io.mapRequired("str3", fb.str3);
+  }
+};
+} // namespace yaml
+} // namespace llvm
+
+TEST(YAMLIO, MultilineStrings) {
+  WithStringField Original;
+  Original.str1 = "a multiline string\nfoobarbaz";
+  Original.str2 = "another one\rfoobarbaz";
+  Original.str3 = "a one-line string";
+
+  std::string Serialized;
+  {
+    llvm::raw_string_ostream OS(Serialized);
+    Output YOut(OS);
+    YOut << Original;
+  }
+  auto Expected = "---\n"
+                  "str1:            'a multiline string\n"
+                  "foobarbaz'\n"
+                  "str2:            'another one\r"
+                  "foobarbaz'\n"
+                  "str3:            a one-line string\n"
+                  "...\n";
+  ASSERT_EQ(Serialized, Expected);
+
+  // Also check it parses back without the errors.
+  WithStringField Deserialized;
+  {
+    Input YIn(Serialized);
+    YIn >> Deserialized;
+    ASSERT_FALSE(YIn.error())
+        << "Parsing error occurred during deserialization. Serialized string:\n"
+        << Serialized;
+  }
+  EXPECT_EQ(Original.str1, Deserialized.str1);
+  EXPECT_EQ(Original.str2, Deserialized.str2);
+  EXPECT_EQ(Original.str3, Deserialized.str3);
+}
+
+TEST(YAMLIO, NoQuotesForTab) {
+  WithStringField WithTab;
+  WithTab.str1 = "aba\tcaba";
+  std::string Serialized;
+  {
+    llvm::raw_string_ostream OS(Serialized);
+    Output YOut(OS);
+    YOut << WithTab;
+  }
+  auto ExpectedPrefix = "---\n"
+                        "str1:            aba\tcaba\n";
+  EXPECT_THAT(Serialized, StartsWith(ExpectedPrefix));
+}
 
 //===----------------------------------------------------------------------===//
 //  Test built-in types




More information about the llvm-commits mailing list