[YAML] Add support for non-printable characters

LLVM IR function names which disable mangling start with '\01'
(https://www.llvm.org/docs/LangRef.html#identifiers).

When an identifier like "\01@abc@" gets dumped to MIR, it is quoted, but
only with single quotes.

http://www.yaml.org/spec/1.2/spec.html#id2770814:

"The allowed character range explicitly excludes the C0 control block
allowed), the surrogate block #xD800-#xDFFF, #xFFFE, and #xFFFF."

http://www.yaml.org/spec/1.2/spec.html#id2776092:

"All non-printable characters must be escaped.
[...]
Note that escape sequences are only interpreted in double-quoted scalars."

This patch adds support for printing escaped non-printable characters
between double quotes if needed.

Should also fix PR31743.

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

llvm-svn: 320996
This commit is contained in:
Francis Visoiu Mistrih 2017-12-18 17:38:03 +00:00
parent 3b753d324c
commit 061acf9c7f
17 changed files with 245 additions and 76 deletions

View File

@ -466,7 +466,7 @@ looks like:
return StringRef();
}
// Determine if this scalar needs quotes.
static bool mustQuote(StringRef) { return true; }
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
};
Block Scalars

View File

@ -56,7 +56,7 @@ template <> struct ScalarTraits<StringValue> {
return "";
}
static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
struct FlowStringValue : StringValue {
@ -73,7 +73,7 @@ template <> struct ScalarTraits<FlowStringValue> {
return ScalarTraits<StringValue>::input(Scalar, Ctx, S);
}
static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
struct BlockStringValue {
@ -120,7 +120,7 @@ template <> struct ScalarTraits<UnsignedValue> {
return ScalarTraits<unsigned>::input(Scalar, Ctx, Value.Value);
}
static bool mustQuote(StringRef Scalar) {
static QuotingType mustQuote(StringRef Scalar) {
return ScalarTraits<unsigned>::mustQuote(Scalar);
}
};

View File

@ -56,7 +56,7 @@ ArrayRef<uint8_t> toDebugH(const DebugHSection &DebugH,
} // end namespace llvm
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::DebugHSection)
LLVM_YAML_DECLARE_SCALAR_TRAITS(CodeViewYAML::GlobalHash, false)
LLVM_YAML_DECLARE_SCALAR_TRAITS(CodeViewYAML::GlobalHash, QuotingType::None)
LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::GlobalHash)
#endif // LLVM_OBJECTYAML_CODEVIEWYAMLTYPES_H

View File

@ -58,7 +58,7 @@ ArrayRef<uint8_t> toDebugT(ArrayRef<LeafRecord>, BumpPtrAllocator &Alloc);
} // end namespace llvm
LLVM_YAML_DECLARE_SCALAR_TRAITS(codeview::GUID, true)
LLVM_YAML_DECLARE_SCALAR_TRAITS(codeview::GUID, QuotingType::Single)
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::LeafRecord)
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::MemberRecord)

View File

@ -261,7 +261,7 @@ using char_16 = char[16];
template <> struct ScalarTraits<char_16> {
static void output(const char_16 &Val, void *, raw_ostream &Out);
static StringRef input(StringRef Scalar, void *, char_16 &Val);
static bool mustQuote(StringRef S);
static QuotingType mustQuote(StringRef S);
};
// This trait is used for UUIDs. It reads and writes them matching otool's
@ -271,7 +271,7 @@ using uuid_t = raw_ostream::uuid_t;
template <> struct ScalarTraits<uuid_t> {
static void output(const uuid_t &Val, void *, raw_ostream &Out);
static StringRef input(StringRef Scalar, void *, uuid_t &Val);
static bool mustQuote(StringRef S);
static QuotingType mustQuote(StringRef S);
};
// Load Command struct mapping traits

View File

@ -107,7 +107,7 @@ inline bool operator==(const BinaryRef &LHS, const BinaryRef &RHS) {
template <> struct ScalarTraits<BinaryRef> {
static void output(const BinaryRef &, void *, raw_ostream &);
static StringRef input(StringRef, void *, BinaryRef &);
static bool mustQuote(StringRef S) { return needsQuotes(S); }
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
} // end namespace yaml

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@ -117,6 +118,11 @@ struct ScalarBitSetTraits {
// static void bitset(IO &io, T &value);
};
/// Describe which type of quotes should be used when quoting is necessary.
/// Some non-printable characters need to be double-quoted, while some others
/// are fine with simple-quoting, and some don't need any quoting.
enum class QuotingType { None, Single, Double };
/// This class should be specialized by type that requires custom conversion
/// to/from a yaml scalar. For example:
///
@ -131,7 +137,7 @@ struct ScalarBitSetTraits {
/// // return empty string on success, or error string
/// return StringRef();
/// }
/// static bool mustQuote(StringRef) { return true; }
/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
/// };
template<typename T>
struct ScalarTraits {
@ -145,7 +151,7 @@ struct ScalarTraits {
//static StringRef input(StringRef scalar, void *ctxt, T &value);
//
// Function to determine if the value should be quoted.
//static bool mustQuote(StringRef);
//static QuotingType mustQuote(StringRef);
};
/// This class should be specialized by type that requires custom conversion
@ -270,7 +276,7 @@ struct has_ScalarTraits
{
using Signature_input = StringRef (*)(StringRef, void*, T&);
using Signature_output = void (*)(const T&, void*, raw_ostream&);
using Signature_mustQuote = bool (*)(StringRef);
using Signature_mustQuote = QuotingType (*)(StringRef);
template <typename U>
static char test(SameType<Signature_input, &U::input> *,
@ -495,28 +501,66 @@ inline bool isBool(StringRef S) {
S.equals("false") || S.equals("False") || S.equals("FALSE");
}
inline bool needsQuotes(StringRef S) {
// 5.1. Character Set
// The allowed character range explicitly excludes the C0 control block #x0-#x1F
// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1
// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate
// block #xD800-#xDFFF, #xFFFE, and #xFFFF.
inline QuotingType needsQuotes(StringRef S) {
if (S.empty())
return true;
return QuotingType::Single;
if (isspace(S.front()) || isspace(S.back()))
return true;
return QuotingType::Single;
if (S.front() == ',')
return true;
static const char ScalarSafeChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t";
if (S.find_first_not_of(ScalarSafeChars) != StringRef::npos)
return true;
return QuotingType::Single;
if (isNull(S))
return true;
return QuotingType::Single;
if (isBool(S))
return true;
return QuotingType::Single;
if (isNumeric(S))
return true;
return QuotingType::Single;
return false;
QuotingType MaxQuotingNeeded = QuotingType::None;
for (unsigned char C : S) {
// Alphanum is safe.
if (isAlnum(C))
continue;
switch (C) {
// Safe scalar characters.
case '_':
case '-':
case '/':
case '^':
case '.':
case ',':
case ' ':
// TAB (0x9), LF (0xA), CR (0xD) and NEL (0x85) are allowed.
case 0x9:
case 0xA:
case 0xD:
case 0x85:
continue;
// DEL (0x7F) are excluded from the allowed character range.
case 0x7F:
return QuotingType::Double;
default: {
// C0 control block (0x0 - 0x1F) is excluded from the allowed character
// range.
if (C <= 0x1F)
return QuotingType::Double;
// C1 control block (0x80 - 0x9F) is excluded from the allowed character
// range.
if (C >= 0x80 && C <= 0x9F)
return QuotingType::Double;
// The character is not safe, at least simple quoting needed.
MaxQuotingNeeded = QuotingType::Single;
}
}
}
return MaxQuotingNeeded;
}
template <typename T, typename Context>
@ -581,7 +625,7 @@ public:
virtual bool bitSetMatch(const char*, bool) = 0;
virtual void endBitSetScalar() = 0;
virtual void scalarString(StringRef &, bool) = 0;
virtual void scalarString(StringRef &, QuotingType) = 0;
virtual void blockScalarString(StringRef &) = 0;
virtual void setError(const Twine &) = 0;
@ -911,91 +955,91 @@ template<>
struct ScalarTraits<bool> {
static void output(const bool &, void* , raw_ostream &);
static StringRef input(StringRef, void *, bool &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<StringRef> {
static void output(const StringRef &, void *, raw_ostream &);
static StringRef input(StringRef, void *, StringRef &);
static bool mustQuote(StringRef S) { return needsQuotes(S); }
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
template<>
struct ScalarTraits<std::string> {
static void output(const std::string &, void *, raw_ostream &);
static StringRef input(StringRef, void *, std::string &);
static bool mustQuote(StringRef S) { return needsQuotes(S); }
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
template<>
struct ScalarTraits<uint8_t> {
static void output(const uint8_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint8_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<uint16_t> {
static void output(const uint16_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint16_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<uint32_t> {
static void output(const uint32_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint32_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<uint64_t> {
static void output(const uint64_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, uint64_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int8_t> {
static void output(const int8_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int8_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int16_t> {
static void output(const int16_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int16_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int32_t> {
static void output(const int32_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int32_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<int64_t> {
static void output(const int64_t &, void *, raw_ostream &);
static StringRef input(StringRef, void *, int64_t &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<float> {
static void output(const float &, void *, raw_ostream &);
static StringRef input(StringRef, void *, float &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<double> {
static void output(const double &, void *, raw_ostream &);
static StringRef input(StringRef, void *, double &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
// For endian types, we just use the existing ScalarTraits for the underlying
@ -1019,7 +1063,7 @@ struct ScalarTraits<support::detail::packed_endian_specific_integral<
return R;
}
static bool mustQuote(StringRef Str) {
static QuotingType mustQuote(StringRef Str) {
return ScalarTraits<value_type>::mustQuote(Str);
}
};
@ -1148,7 +1192,7 @@ private:
bool beginBitSetScalar(bool &) override;
bool bitSetMatch(const char *, bool ) override;
void endBitSetScalar() override;
void scalarString(StringRef &, bool) override;
void scalarString(StringRef &, QuotingType) override;
void blockScalarString(StringRef &) override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
@ -1293,7 +1337,7 @@ public:
bool beginBitSetScalar(bool &) override;
bool bitSetMatch(const char *, bool ) override;
void endBitSetScalar() override;
void scalarString(StringRef &, bool) override;
void scalarString(StringRef &, QuotingType) override;
void blockScalarString(StringRef &) override;
void setError(const Twine &message) override;
bool canElideEmptySequence() override;
@ -1371,28 +1415,28 @@ template<>
struct ScalarTraits<Hex8> {
static void output(const Hex8 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex8 &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<Hex16> {
static void output(const Hex16 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex16 &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<Hex32> {
static void output(const Hex32 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex32 &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template<>
struct ScalarTraits<Hex64> {
static void output(const Hex64 &, void *, raw_ostream &);
static StringRef input(StringRef, void *, Hex64 &);
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
// Define non-member operator>> so that Input can stream in a document list.
@ -1681,7 +1725,7 @@ template <typename T> struct StdMapStringCustomMappingTraitsImpl {
template <> struct ScalarTraits<Type> { \
static void output(const Type &Value, void *ctx, raw_ostream &Out); \
static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \
static bool mustQuote(StringRef) { return MustQuote; } \
static QuotingType mustQuote(StringRef) { return MustQuote; } \
}; \
} \
}

View File

@ -66,7 +66,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport)
LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport)
LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData)
LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, false)
LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None)
LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)
LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)
LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)

View File

@ -42,8 +42,8 @@ using namespace llvm::yaml;
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex)
// We only need to declare these, the definitions are in CodeViewYAMLTypes.cpp
LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, false)
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, false)
LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, QuotingType::None)
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, QuotingType::None)
LLVM_YAML_DECLARE_ENUM_TRAITS(SymbolKind)
LLVM_YAML_DECLARE_ENUM_TRAITS(FrameCookieKind)
@ -62,7 +62,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(ThunkOrdinal)
LLVM_YAML_STRONG_TYPEDEF(StringRef, TypeName)
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeName, true)
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeName, QuotingType::Single)
StringRef ScalarTraits<TypeName>::input(StringRef S, void *V, TypeName &T) {
return ScalarTraits<StringRef>::input(S, V, T.value);

View File

@ -48,8 +48,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(OneMethodRecord)
LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind)
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex)
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, false)
LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, false)
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, QuotingType::None)
LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, QuotingType::None)
LLVM_YAML_DECLARE_ENUM_TRAITS(TypeLeafKind)
LLVM_YAML_DECLARE_ENUM_TRAITS(PointerToMemberRepresentation)

View File

@ -52,7 +52,9 @@ StringRef ScalarTraits<char_16>::input(StringRef Scalar, void *, char_16 &Val) {
return StringRef();
}
bool ScalarTraits<char_16>::mustQuote(StringRef S) { return needsQuotes(S); }
QuotingType ScalarTraits<char_16>::mustQuote(StringRef S) {
return needsQuotes(S);
}
void ScalarTraits<uuid_t>::output(const uuid_t &Val, void *, raw_ostream &Out) {
Out.write_uuid(Val);
@ -75,7 +77,9 @@ StringRef ScalarTraits<uuid_t>::input(StringRef Scalar, void *, uuid_t &Val) {
return StringRef();
}
bool ScalarTraits<uuid_t>::mustQuote(StringRef S) { return needsQuotes(S); }
QuotingType ScalarTraits<uuid_t>::mustQuote(StringRef S) {
return needsQuotes(S);
}
void MappingTraits<MachOYAML::FileHeader>::mapping(
IO &IO, MachOYAML::FileHeader &FileHdr) {

View File

@ -168,9 +168,10 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) {
const char *delim = "";
for (const Statistic *Stat : Stats.Stats) {
OS << delim;
assert(!yaml::needsQuotes(Stat->getDebugType()) &&
assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None &&
"Statistic group/type name is simple.");
assert(!yaml::needsQuotes(Stat->getName()) && "Statistic name is simple");
assert(yaml::needsQuotes(Stat->getName()) == yaml::QuotingType::None &&
"Statistic name is simple");
OS << "\t\"" << Stat->getDebugType() << '.' << Stat->getName() << "\": "
<< Stat->getValue();
delim = ",\n";

View File

@ -362,8 +362,10 @@ void TimerGroup::printAll(raw_ostream &OS) {
void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
const char *suffix, double Value) {
assert(!yaml::needsQuotes(Name) && "TimerGroup name needs no quotes");
assert(!yaml::needsQuotes(R.Name) && "Timer name needs no quotes");
assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
"TimerGroup name needs no quotes");
assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
"Timer name needs no quotes");
OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value;
}

View File

@ -19,6 +19,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Unicode.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@ -330,7 +331,7 @@ void Input::endBitSetScalar() {
}
}
void Input::scalarString(StringRef &S, bool) {
void Input::scalarString(StringRef &S, QuotingType) {
if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
S = SN->value();
} else {
@ -338,7 +339,7 @@ void Input::scalarString(StringRef &S, bool) {
}
}
void Input::blockScalarString(StringRef &S) { scalarString(S, false); }
void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); }
void Input::setError(HNode *hnode, const Twine &message) {
assert(hnode && "HNode must not be NULL");
@ -617,7 +618,7 @@ void Output::endBitSetScalar() {
this->outputUpToEndOfLine(" ]");
}
void Output::scalarString(StringRef &S, bool MustQuote) {
void Output::scalarString(StringRef &S, QuotingType MustQuote) {
this->newLineCheck();
if (S.empty()) {
// Print '' for the empty string because leaving the field empty is not
@ -625,27 +626,52 @@ void Output::scalarString(StringRef &S, bool MustQuote) {
this->outputUpToEndOfLine("''");
return;
}
if (!MustQuote) {
if (MustQuote == QuotingType::None) {
// Only quote if we must.
this->outputUpToEndOfLine(S);
return;
}
unsigned i = 0;
unsigned j = 0;
unsigned End = S.size();
output("'"); // Starting single quote.
const char *Base = S.data();
const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\"";
const char QuoteChar = MustQuote == QuotingType::Single ? '\'' : '"';
output(Quote); // Starting quote.
// When using single-quoted strings, any single quote ' must be doubled to be
// escaped.
// When using double-quoted strings, print \x + hex for non-printable ASCII
// characters, and escape double quotes.
while (j < End) {
// Escape a single quote by doubling it.
if (S[j] == '\'') {
output(StringRef(&Base[i], j - i + 1));
output("'");
if (S[j] == QuoteChar) { // Escape quotes.
output(StringRef(&Base[i], j - i)); // "flush".
if (MustQuote == QuotingType::Double) { // Print it as \"
output(StringLiteral("\\"));
output(StringRef(Quote, 1));
} else { // Single
output(StringLiteral("''")); // Print it as ''
}
i = j + 1;
} else if (MustQuote == QuotingType::Double &&
!sys::unicode::isPrintable(S[j])) {
output(StringRef(&Base[i], j - i)); // "flush"
output(StringLiteral("\\x"));
// Output the byte 0x0F as \x0f.
auto FormattedHex = format_hex_no_prefix(S[j], 2);
Out << FormattedHex;
Column += 4; // one for the '\', one for the 'x', and two for the hex
i = j + 1;
}
++j;
}
output(StringRef(&Base[i], j - i));
this->outputUpToEndOfLine("'"); // Ending single quote.
this->outputUpToEndOfLine(Quote); // Ending quote.
}
void Output::blockScalarString(StringRef &S) {

View File

@ -0,0 +1,6 @@
; RUN: llc -mtriple=x86_64-unknown-unknown -stop-after branch-folder -o - %s 2>&1 | FileCheck %s
define void @"\01?f@@YAXXZ"() {
; CHECK: name: "\x01?f@@YAXXZ"
ret void
}

View File

@ -232,7 +232,7 @@ template <> struct MappingTraits<dsymutil::DebugMapObject> {
template <> struct ScalarTraits<Triple> {
static void output(const Triple &val, void *, raw_ostream &out);
static StringRef input(StringRef scalar, void *, Triple &value);
static bool mustQuote(StringRef) { return true; }
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
};
template <>

View File

@ -860,7 +860,7 @@ namespace yaml {
return "malformed by";
}
}
static bool mustQuote(StringRef) { return true; }
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
};
}
}
@ -1064,7 +1064,7 @@ namespace yaml {
return StringRef();
}
static bool mustQuote(StringRef) { return false; }
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template <> struct ScalarTraits<MyString> {
@ -1075,7 +1075,9 @@ namespace yaml {
static StringRef input(StringRef S, void *Ctx, MyString &V) {
return Impl::input(S, Ctx, V.value);
}
static bool mustQuote(StringRef S) { return Impl::mustQuote(S); }
static QuotingType mustQuote(StringRef S) {
return Impl::mustQuote(S);
}
};
}
}
@ -2232,7 +2234,7 @@ struct ScalarTraits<FlowSeq> {
return "";
}
static bool mustQuote(StringRef S) { return false; }
static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
};
}
}
@ -2455,3 +2457,87 @@ TEST(YAMLIO, InvalidInput) {
yin >> Data;
EXPECT_TRUE((bool)yin.error());
}
TEST(YAMLIO, TestEscapedSingleQuote) {
std::string Id = "@abc@";
std::string out;
llvm::raw_string_ostream ostr(out);
Output xout(ostr, nullptr, 0);
llvm::yaml::EmptyContext Ctx;
yamlize(xout, Id, true, Ctx);
ostr.flush();
EXPECT_EQ("'@abc@'", out);
}
TEST(YAMLIO, TestEscapedNoQuote) {
std::string Id = "abc/";
std::string out;
llvm::raw_string_ostream ostr(out);
Output xout(ostr, nullptr, 0);
llvm::yaml::EmptyContext Ctx;
yamlize(xout, Id, true, Ctx);
ostr.flush();
EXPECT_EQ("abc/", out);
}
TEST(YAMLIO, TestEscapedDoubleQuoteNonPrintable) {
std::string Id = "\01@abc@";
std::string out;
llvm::raw_string_ostream ostr(out);
Output xout(ostr, nullptr, 0);
llvm::yaml::EmptyContext Ctx;
yamlize(xout, Id, true, Ctx);
ostr.flush();
EXPECT_EQ("\"\\x01@abc@\"", out);
}
TEST(YAMLIO, TestEscapedDoubleQuoteInsideSingleQuote) {
std::string Id = "abc\"fdf";
std::string out;
llvm::raw_string_ostream ostr(out);
Output xout(ostr, nullptr, 0);
llvm::yaml::EmptyContext Ctx;
yamlize(xout, Id, true, Ctx);
ostr.flush();
EXPECT_EQ("'abc\"fdf'", out);
}
TEST(YAMLIO, TestEscapedDoubleQuoteInsideDoubleQuote) {
std::string Id = "\01bc\"fdf";
std::string out;
llvm::raw_string_ostream ostr(out);
Output xout(ostr, nullptr, 0);
llvm::yaml::EmptyContext Ctx;
yamlize(xout, Id, true, Ctx);
ostr.flush();
EXPECT_EQ("\"\\x01bc\\\"fdf\"", out);
}
TEST(YAMLIO, TestEscapedSingleQuoteInsideSingleQuote) {
std::string Id = "abc'fdf";
std::string out;
llvm::raw_string_ostream ostr(out);
Output xout(ostr, nullptr, 0);
llvm::yaml::EmptyContext Ctx;
yamlize(xout, Id, true, Ctx);
ostr.flush();
EXPECT_EQ("'abc''fdf'", out);
}