aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2018-05-30 10:40:11 +0000
committerIlya Biryukov <ibiryukov@google.com>2018-05-30 10:40:11 +0000
commitcab5faf1e22c36a6ff561001ce830910cee4de76 (patch)
tree8b4ba071a63fbffcdd456a99ae4eb2d7d2d020f8
parentadcf643e71823ecd2e9abe12b52e5a06c13ac1fd (diff)
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@333527 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Support/YAMLTraits.h7
-rw-r--r--unittests/Support/YAMLIOTest.cpp68
2 files changed, 73 insertions, 2 deletions
diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h
index 06eafc0dfd8..4b8c4e95828 100644
--- a/include/llvm/Support/YAMLTraits.h
+++ b/include/llvm/Support/YAMLTraits.h
@@ -540,11 +540,14 @@ inline QuotingType needsQuotes(StringRef S) {
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:
diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp
index 378662c7923..13364806524 100644
--- a/unittests/Support/YAMLIOTest.cpp
+++ b/unittests/Support/YAMLIOTest.cpp
@@ -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