https://github.com/Nerixyz updated 
https://github.com/llvm/llvm-project/pull/143177

>From 519f0899e79a08c5a3548923e188747af8c6f764 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerix...@outlook.de>
Date: Fri, 6 Jun 2025 19:23:04 +0200
Subject: [PATCH] [LLDB] Add type summaries for MSVC STL strings

---
 .../lldb/DataFormatters/StringPrinter.h       |  15 ++
 .../include/lldb/DataFormatters/TypeSummary.h |  99 +++++++++--
 .../lldb/DataFormatters/ValueObjectPrinter.h  |   2 +-
 lldb/packages/Python/lldbsuite/test/dotest.py |  21 +++
 .../Python/lldbsuite/test/test_categories.py  |   1 +
 lldb/source/API/SBTypeSummary.cpp             |  10 +-
 lldb/source/Commands/CommandObjectType.cpp    |   7 +-
 lldb/source/DataFormatters/TypeSummary.cpp    | 147 ++++++++++++----
 .../Plugins/Language/CPlusPlus/CMakeLists.txt |   1 +
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp  | 146 ++++++++++++----
 .../Language/CPlusPlus/CxxStringTypes.cpp     | 158 +++++++++++++++++-
 .../Language/CPlusPlus/CxxStringTypes.h       |  35 ++++
 .../Plugins/Language/CPlusPlus/LibCxx.cpp     | 121 +-------------
 .../Plugins/Language/CPlusPlus/MsvcStl.cpp    | 140 ++++++++++++++++
 .../Plugins/Language/CPlusPlus/MsvcStl.h      |  33 ++++
 .../string/TestDataFormatterLibcxxString.py   |   8 +-
 .../TestDataFormatterLibcxxStringView.py      |   8 +-
 .../msvcstl/string/Makefile                   |   4 +
 .../string/TestDataFormatterStdString.py      | 117 +++++++++++++
 .../msvcstl/string/main.cpp                   |  38 +++++
 .../msvcstl/u8string/Makefile                 |   4 +
 .../u8string/TestDataFormatterStdU8String.py  |  31 ++++
 .../msvcstl/u8string/main.cpp                 |  14 ++
 23 files changed, 951 insertions(+), 209 deletions(-)
 create mode 100644 lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
 create mode 100644 lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
 create mode 100644 
lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/Makefile
 create mode 100644 
lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/TestDataFormatterStdString.py
 create mode 100644 
lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/main.cpp
 create mode 100644 
lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/Makefile
 create mode 100644 
lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/TestDataFormatterStdU8String.py
 create mode 100644 
lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/main.cpp

diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h 
b/lldb/include/lldb/DataFormatters/StringPrinter.h
index 4169f53e63f38..4ebe712be60e1 100644
--- a/lldb/include/lldb/DataFormatters/StringPrinter.h
+++ b/lldb/include/lldb/DataFormatters/StringPrinter.h
@@ -152,6 +152,21 @@ class StringPrinter {
   template <StringElementType element_type>
   static bool
   ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options);
+
+  template <StringElementType element_type>
+  static constexpr uint64_t ElementByteSize() {
+    switch (element_type) {
+    case StringElementType::ASCII:
+    case StringElementType::UTF8:
+      return 1;
+    case StringElementType::UTF16:
+      return 2;
+    case StringElementType::UTF32:
+      return 3;
+    default:
+      return 0;
+    }
+  }
 };
 
 } // namespace formatters
diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h 
b/lldb/include/lldb/DataFormatters/TypeSummary.h
index 589f68c2ce314..95d7a2a079e07 100644
--- a/lldb/include/lldb/DataFormatters/TypeSummary.h
+++ b/lldb/include/lldb/DataFormatters/TypeSummary.h
@@ -48,7 +48,14 @@ class TypeSummaryOptions {
 
 class TypeSummaryImpl {
 public:
-  enum class Kind { eSummaryString, eScript, eBytecode, eCallback, eInternal };
+  enum class Kind {
+    eSummaryString,
+    eScript,
+    eBytecode,
+    eCallback,
+    eCascading,
+    eInternal
+  };
 
   virtual ~TypeSummaryImpl() = default;
 
@@ -292,18 +299,29 @@ class TypeSummaryImpl {
   const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete;
 };
 
-// simple string-based summaries, using ${var to show data
-struct StringSummaryFormat : public TypeSummaryImpl {
+struct StringSummaryData {
   std::string m_format_str;
   FormatEntity::Entry m_format;
   Status m_error;
 
+  StringSummaryData(const char *f);
+  void SetFormat(const char *f);
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options,
+                    const TypeSummaryImpl &summary);
+};
+
+// simple string-based summaries, using ${var to show data
+struct StringSummaryFormat : public TypeSummaryImpl {
+  StringSummaryData m_data;
+
   StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f,
                       uint32_t ptr_match_depth = 1);
 
   ~StringSummaryFormat() override = default;
 
-  const char *GetSummaryString() const { return m_format_str.c_str(); }
+  const char *GetSummaryString() const { return m_data.m_format_str.c_str(); }
 
   void SetSummaryString(const char *f);
 
@@ -323,15 +341,23 @@ struct StringSummaryFormat : public TypeSummaryImpl {
   const StringSummaryFormat &operator=(const StringSummaryFormat &) = delete;
 };
 
-// summaries implemented via a C++ function
-struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
+struct CXXFunctionSummaryData {
   // we should convert these to SBValue and SBStream if we ever cross the
   // boundary towards the external world
-  typedef std::function<bool(ValueObject &, Stream &,
-                             const TypeSummaryOptions &)>
-      Callback;
+  using Callback =
+      std::function<bool(ValueObject &, Stream &, const TypeSummaryOptions &)>;
 
   Callback m_impl;
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options,
+                    const TypeSummaryImpl &summary);
+};
+
+// summaries implemented via a C++ function
+struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
+  using Callback = CXXFunctionSummaryData::Callback;
+  CXXFunctionSummaryData m_data;
   std::string m_description;
 
   CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl,
@@ -340,11 +366,13 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
 
   ~CXXFunctionSummaryFormat() override = default;
 
-  Callback GetBackendFunction() const { return m_impl; }
+  Callback GetBackendFunction() const { return m_data.m_impl; }
 
   const char *GetTextualInfo() const { return m_description.c_str(); }
 
-  void SetBackendFunction(Callback cb_func) { m_impl = std::move(cb_func); }
+  void SetBackendFunction(Callback cb_func) {
+    m_data.m_impl = std::move(cb_func);
+  }
 
   void SetTextualInfo(const char *descr) {
     if (descr)
@@ -372,6 +400,55 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
   operator=(const CXXFunctionSummaryFormat &) = delete;
 };
 
+// Multiple summaries for the same type name but different type layouts.
+// A validator function checks the layout.
+struct CXXCascadingSummaryFormat : public TypeSummaryImpl {
+  using Validator = bool(ValueObject &valobj);
+  using Impl = std::variant<CXXFunctionSummaryData, StringSummaryData>;
+  using ImplEntry = std::pair<Validator *, Impl>;
+  using ImplList = llvm::SmallVector<ImplEntry, 2>;
+
+  ImplList m_impls;
+  std::string m_description;
+
+  CXXCascadingSummaryFormat(const TypeSummaryImpl::Flags &flags,
+                            const char *description, ImplList impls = {},
+                            uint32_t ptr_match_depth = 1);
+
+  ~CXXCascadingSummaryFormat() override = default;
+
+  const char *GetTextualInfo() const { return m_description.c_str(); }
+
+  CXXCascadingSummaryFormat *Append(Validator *validator, Impl impl);
+
+  void SetTextualInfo(const char *descr) {
+    if (descr)
+      m_description.assign(descr);
+    else
+      m_description.clear();
+  }
+
+  ImplList CopyImpls() const;
+
+  bool FormatObject(ValueObject *valobj, std::string &dest,
+                    const TypeSummaryOptions &options) override;
+
+  std::string GetDescription() override;
+
+  static bool classof(const TypeSummaryImpl *S) {
+    return S->GetKind() == Kind::eCascading;
+  }
+
+  std::string GetName() override;
+
+  using SharedPointer = std::shared_ptr<CXXCascadingSummaryFormat>;
+
+private:
+  CXXCascadingSummaryFormat(const CXXCascadingSummaryFormat &) = delete;
+  const CXXCascadingSummaryFormat &
+  operator=(const CXXCascadingSummaryFormat &) = delete;
+};
+
 // Python-based summaries, running script code to show data
 struct ScriptSummaryFormat : public TypeSummaryImpl {
   std::string m_function_name;
diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h 
b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
index f9deb6ebf8d6d..1f20c3180d37a 100644
--- a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -165,7 +165,7 @@ class ValueObjectPrinter {
   std::string m_error;
   bool m_val_summary_ok;
 
-  friend struct StringSummaryFormat;
+  friend struct StringSummaryData;
 
   ValueObjectPrinter(const ValueObjectPrinter &) = delete;
   const ValueObjectPrinter &operator=(const ValueObjectPrinter &) = delete;
diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py 
b/lldb/packages/Python/lldbsuite/test/dotest.py
index d7f274ac4f60e..7f15be206acb8 100644
--- a/lldb/packages/Python/lldbsuite/test/dotest.py
+++ b/lldb/packages/Python/lldbsuite/test/dotest.py
@@ -831,6 +831,26 @@ def checkLibstdcxxSupport():
     configuration.skip_categories.append("libstdcxx")
 
 
+def canRunMsvcStlTests():
+    from lldbsuite.test import lldbplatformutil
+
+    platform = lldbplatformutil.getPlatform()
+    if platform == "windows":
+        return True, "MSVC STL is present on Windows"
+    return False, f"Don't know how to build with MSVC's STL on {platform}"
+
+
+def checkMsvcStlSupport():
+    result, reason = canRunMsvcStlTests()
+    if result:
+        return  # msvcstl supported
+    if "msvcstl" in configuration.categories_list:
+        return  # msvcstl category explicitly requested, let it run.
+    if configuration.verbose:
+        print(f"msvcstl tests will not be run because: {reason}")
+    configuration.skip_categories.append("msvcstl")
+
+
 def canRunWatchpointTests():
     from lldbsuite.test import lldbplatformutil
 
@@ -1044,6 +1064,7 @@ def run_suite():
 
     checkLibcxxSupport()
     checkLibstdcxxSupport()
+    checkMsvcStlSupport()
     checkWatchpointSupport()
     checkDebugInfoSupport()
     checkDebugServerSupport()
diff --git a/lldb/packages/Python/lldbsuite/test/test_categories.py 
b/lldb/packages/Python/lldbsuite/test/test_categories.py
index b585f695adeab..1f6e8a78e0c0d 100644
--- a/lldb/packages/Python/lldbsuite/test/test_categories.py
+++ b/lldb/packages/Python/lldbsuite/test/test_categories.py
@@ -33,6 +33,7 @@
     "lldb-server": "Tests related to lldb-server",
     "lldb-dap": "Tests for the Debug Adapter Protocol with lldb-dap",
     "llgs": "Tests for the gdb-server functionality of lldb-server",
+    "msvcstl": "Test for MSVC STL data formatters",
     "pexpect": "Tests requiring the pexpect library to be available",
     "objc": "Tests related to the Objective-C programming language support",
     "pyapi": "Tests related to the Python API",
diff --git a/lldb/source/API/SBTypeSummary.cpp 
b/lldb/source/API/SBTypeSummary.cpp
index 58ec068ab9600..ef7e22b1a79af 100644
--- a/lldb/source/API/SBTypeSummary.cpp
+++ b/lldb/source/API/SBTypeSummary.cpp
@@ -370,6 +370,9 @@ bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
     if (IsSummaryString() != rhs.IsSummaryString())
       return false;
     return GetOptions() == rhs.GetOptions();
+  case TypeSummaryImpl::Kind::eCascading:
+    return llvm::dyn_cast<CXXCascadingSummaryFormat>(m_opaque_sp.get()) ==
+           llvm::dyn_cast<CXXCascadingSummaryFormat>(rhs.m_opaque_sp.get());
   case TypeSummaryImpl::Kind::eInternal:
     return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
   }
@@ -406,7 +409,7 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
   if (CXXFunctionSummaryFormat *current_summary_ptr =
           llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get())) {
     new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(
-        GetOptions(), current_summary_ptr->m_impl,
+        GetOptions(), current_summary_ptr->m_data.m_impl,
         current_summary_ptr->m_description.c_str()));
   } else if (ScriptSummaryFormat *current_summary_ptr =
                  llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
@@ -417,6 +420,11 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
     new_sp = TypeSummaryImplSP(new StringSummaryFormat(
         GetOptions(), current_summary_ptr->GetSummaryString()));
+  } else if (CXXCascadingSummaryFormat *current_summary_ptr =
+                 llvm::dyn_cast<CXXCascadingSummaryFormat>(m_opaque_sp.get())) 
{
+    new_sp = TypeSummaryImplSP(new CXXCascadingSummaryFormat(
+        GetOptions(), current_summary_ptr->GetTextualInfo(),
+        current_summary_ptr->CopyImpls()));
   }
 
   SetSP(new_sp);
diff --git a/lldb/source/Commands/CommandObjectType.cpp 
b/lldb/source/Commands/CommandObjectType.cpp
index 19cd3ff2972e9..bd6138a860caa 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -1397,9 +1397,10 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
     result.AppendError("summary creation failed");
     return false;
   }
-  if (string_format->m_error.Fail()) {
-    result.AppendErrorWithFormat("syntax error: %s",
-                                 
string_format->m_error.AsCString("<unknown>"));
+  if (string_format->m_data.m_error.Fail()) {
+    result.AppendErrorWithFormat(
+        "syntax error: %s",
+        string_format->m_data.m_error.AsCString("<unknown>"));
     return false;
   }
   lldb::TypeSummaryImplSP entry(string_format.release());
diff --git a/lldb/source/DataFormatters/TypeSummary.cpp 
b/lldb/source/DataFormatters/TypeSummary.cpp
index 6aa290698cd12..532e14f6f0aba 100644
--- a/lldb/source/DataFormatters/TypeSummary.cpp
+++ b/lldb/source/DataFormatters/TypeSummary.cpp
@@ -57,33 +57,40 @@ std::string TypeSummaryImpl::GetSummaryKindName() {
     return "python";
   case Kind::eInternal:
     return "c++";
+  case Kind::eCascading:
+    return "cascading";
   case Kind::eBytecode:
     return "bytecode";
   }
   llvm_unreachable("Unknown type kind name");
 }
 
-StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
-                                         const char *format_cstr,
-                                         uint32_t ptr_match_depth)
-    : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth),
-      m_format_str() {
-  SetSummaryString(format_cstr);
-}
+StringSummaryData::StringSummaryData(const char *f) { SetFormat(f); }
 
-void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
+void StringSummaryData::SetFormat(const char *f) {
   m_format.Clear();
-  if (format_cstr && format_cstr[0]) {
-    m_format_str = format_cstr;
-    m_error = FormatEntity::Parse(format_cstr, m_format);
+  if (f && f[0]) {
+    m_format_str = f;
+    m_error = FormatEntity::Parse(f, m_format);
   } else {
     m_format_str.clear();
     m_error.Clear();
   }
 }
 
-bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string 
&retval,
-                                       const TypeSummaryOptions &options) {
+StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
+                                         const char *format_cstr,
+                                         uint32_t ptr_match_depth)
+    : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth),
+      m_data(format_cstr) {}
+
+void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
+  m_data.SetFormat(format_cstr);
+}
+
+bool StringSummaryData::FormatObject(ValueObject *valobj, std::string &retval,
+                                     const TypeSummaryOptions &options,
+                                     const TypeSummaryImpl &summary) {
   if (!valobj) {
     retval.assign("NULL ValueObject");
     return false;
@@ -96,12 +103,12 @@ bool StringSummaryFormat::FormatObject(ValueObject 
*valobj, std::string &retval,
   if (frame)
     sc = frame->GetSymbolContext(lldb::eSymbolContextEverything);
 
-  if (IsOneLiner()) {
+  if (summary.IsOneLiner()) {
     // We've already checked the case of a NULL valobj above.  Let's put in an
     // assert here to make sure someone doesn't take that out:
     assert(valobj && "Must have a valid ValueObject to summarize");
     ValueObjectPrinter printer(*valobj, &s, DumpValueObjectOptions());
-    printer.PrintChildrenOneLiner(HideNames(valobj));
+    printer.PrintChildrenOneLiner(summary.HideNames(valobj));
     retval = std::string(s.GetString());
     return true;
   } else {
@@ -117,40 +124,52 @@ bool StringSummaryFormat::FormatObject(ValueObject 
*valobj, std::string &retval,
   }
 }
 
+bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string 
&retval,
+                                       const TypeSummaryOptions &options) {
+  return m_data.FormatObject(valobj, retval, options, *this);
+}
+
 std::string StringSummaryFormat::GetDescription() {
   StreamString sstr;
 
-  sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", 
m_format_str.c_str(),
-              m_error.Fail() ? " error: " : "",
-              m_error.Fail() ? m_error.AsCString() : "",
-              Cascades() ? "" : " (not cascading)",
-              !DoesPrintChildren(nullptr) ? "" : " (show children)",
-              !DoesPrintValue(nullptr) ? " (hide value)" : "",
-              IsOneLiner() ? " (one-line printout)" : "",
-              SkipsPointers() ? " (skip pointers)" : "",
-              SkipsReferences() ? " (skip references)" : "",
-              HideNames(nullptr) ? " (hide member names)" : "",
-              GetPtrMatchDepth());
+  sstr.Printf(
+      "`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", m_data.m_format_str.c_str(),
+      m_data.m_error.Fail() ? " error: " : "",
+      m_data.m_error.Fail() ? m_data.m_error.AsCString() : "",
+      Cascades() ? "" : " (not cascading)",
+      !DoesPrintChildren(nullptr) ? "" : " (show children)",
+      !DoesPrintValue(nullptr) ? " (hide value)" : "",
+      IsOneLiner() ? " (one-line printout)" : "",
+      SkipsPointers() ? " (skip pointers)" : "",
+      SkipsReferences() ? " (skip references)" : "",
+      HideNames(nullptr) ? " (hide member names)" : "", GetPtrMatchDepth());
   return std::string(sstr.GetString());
 }
 
-std::string StringSummaryFormat::GetName() { return m_format_str; }
+std::string StringSummaryFormat::GetName() { return m_data.m_format_str; }
+
+bool CXXFunctionSummaryData::FormatObject(ValueObject *valobj,
+                                          std::string &dest,
+                                          const TypeSummaryOptions &options,
+                                          const TypeSummaryImpl &summary) {
+  dest.clear();
+  StreamString stream;
+  if (!m_impl || !m_impl(*valobj, stream, options))
+    return false;
+  dest = std::string(stream.GetString());
+  return true;
+}
 
 CXXFunctionSummaryFormat::CXXFunctionSummaryFormat(
     const TypeSummaryImpl::Flags &flags, Callback impl, const char 
*description,
     uint32_t ptr_match_depth)
-    : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_impl(impl),
+    : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_data{impl},
       m_description(description ? description : "") {}
 
 bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
                                             std::string &dest,
                                             const TypeSummaryOptions &options) 
{
-  dest.clear();
-  StreamString stream;
-  if (!m_impl || !m_impl(*valobj, stream, options))
-    return false;
-  dest = std::string(stream.GetString());
-  return true;
+  return m_data.FormatObject(valobj, dest, options, *this);
 }
 
 std::string CXXFunctionSummaryFormat::GetDescription() {
@@ -169,6 +188,66 @@ std::string CXXFunctionSummaryFormat::GetDescription() {
 
 std::string CXXFunctionSummaryFormat::GetName() { return m_description; }
 
+CXXCascadingSummaryFormat::CXXCascadingSummaryFormat(
+    const TypeSummaryImpl::Flags &flags, const char *description,
+    ImplList impls, uint32_t ptr_match_depth)
+    : TypeSummaryImpl(Kind::eCascading, flags, ptr_match_depth),
+      m_impls(std::move(impls)) {}
+
+CXXCascadingSummaryFormat *
+CXXCascadingSummaryFormat::Append(Validator *validator, Impl impl) {
+  m_impls.emplace_back(validator, std::move(impl));
+  return this;
+}
+
+CXXCascadingSummaryFormat::ImplList
+CXXCascadingSummaryFormat::CopyImpls() const {
+  auto copy_impl = [](const ImplEntry &entry) -> ImplEntry {
+    return {entry.first,
+            std::visit(
+                llvm::makeVisitor(
+                    [](const CXXFunctionSummaryData &fn) -> Impl { return fn; 
},
+                    [](const StringSummaryData &string) -> Impl {
+                      return StringSummaryData(string.m_format_str.c_str());
+                    }),
+                entry.second)};
+  };
+  return {llvm::map_iterator(m_impls.begin(), copy_impl),
+          llvm::map_iterator(m_impls.end(), copy_impl)};
+}
+
+bool CXXCascadingSummaryFormat::FormatObject(
+    ValueObject *valobj, std::string &dest, const TypeSummaryOptions &options) 
{
+  if (!valobj)
+    return false;
+
+  for (auto &[validator, impl] : m_impls) {
+    if (!validator || validator(*valobj))
+      return std::visit(
+          [&](auto &impl) {
+            return impl.FormatObject(valobj, dest, options, *this);
+          },
+          impl);
+  }
+  return false;
+}
+
+std::string CXXCascadingSummaryFormat::GetDescription() {
+  StreamString sstr;
+  sstr.Printf("size=%zu %s%s%s%s%s%s%s ptr-match-depth=%u %s", m_impls.size(),
+              Cascades() ? "" : " (not cascading)",
+              !DoesPrintChildren(nullptr) ? "" : " (show children)",
+              !DoesPrintValue(nullptr) ? " (hide value)" : "",
+              IsOneLiner() ? " (one-line printout)" : "",
+              SkipsPointers() ? " (skip pointers)" : "",
+              SkipsReferences() ? " (skip references)" : "",
+              HideNames(nullptr) ? " (hide member names)" : "",
+              GetPtrMatchDepth(), m_description.c_str());
+  return std::string(sstr.GetString());
+}
+
+std::string CXXCascadingSummaryFormat::GetName() { return m_description; }
+
 ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags,
                                          const char *function_name,
                                          const char *python_script,
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt 
b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index 5ba2567c80cc3..bbfc31a722f27 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -32,6 +32,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
   LibStdcpp.cpp
   LibStdcppTuple.cpp
   LibStdcppUniquePointer.cpp
+  MsvcStl.cpp
   MSVCUndecoratedNameParser.cpp
 
   LINK_COMPONENTS
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 0f18abb47591d..b99c0c711ba2f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -46,6 +46,7 @@
 #include "LibCxxVariant.h"
 #include "LibStdcpp.h"
 #include "MSVCUndecoratedNameParser.h"
+#include "MsvcStl.h"
 #include "lldb/lldb-enumerations.h"
 
 using namespace lldb;
@@ -1372,6 +1373,42 @@ static void 
LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
           "${var.__y_} ${var.__m_} ${var.__wdl_}")));
 }
 
+static bool IsMsvcStdStringType(ValueObject &valobj) {
+  std::vector<uint32_t> indexes;
+  return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", 
true,
+                                                                indexes) > 0;
+}
+
+static void RegisterStdStringSummaryProvider(
+    const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
+    llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
+  auto makeSpecifier = [](llvm::StringRef name) {
+    return std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+        name, eFormatterMatchExact);
+  };
+
+  category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
+
+  // std::basic_string<char>
+  category_sp->AddTypeSummary(
+      makeSpecifier((llvm::Twine("std::basic_string<") + char_ty + ">").str()),
+      summary_sp);
+  // std::basic_string<char,std::char_traits<char>,std::allocator<char> >
+  category_sp->AddTypeSummary(
+      makeSpecifier((llvm::Twine("std::basic_string<") + char_ty +
+                     ",std::char_traits<" + char_ty + ">,std::allocator<" +
+                     char_ty + "> >")
+                        .str()),
+      summary_sp);
+  // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+  category_sp->AddTypeSummary(
+      makeSpecifier((llvm::Twine("std::basic_string<") + char_ty +
+                     ", std::char_traits<" + char_ty + ">, std::allocator<" +
+                     char_ty + "> >")
+                        .str()),
+      summary_sp);
+}
+
 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
   if (!cpp_category_sp)
     return;
@@ -1385,9 +1422,6 @@ static void 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
       .SetShowMembersOneLiner(false)
       .SetHideItemNames(false);
 
-  lldb::TypeSummaryImplSP std_string_summary_sp(
-      new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
-
   lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
       stl_summary_flags, LibStdcppStringSummaryProvider,
       "libstdc++ c++11 std::string summary provider"));
@@ -1395,17 +1429,6 @@ static void 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
       stl_summary_flags, LibStdcppWStringSummaryProvider,
       "libstdc++ c++11 std::wstring summary provider"));
 
-  cpp_category_sp->AddTypeSummary("std::string", eFormatterMatchExact,
-                                  std_string_summary_sp);
-  cpp_category_sp->AddTypeSummary("std::basic_string<char>",
-                                  eFormatterMatchExact, std_string_summary_sp);
-  cpp_category_sp->AddTypeSummary(
-      "std::basic_string<char,std::char_traits<char>,std::allocator<char> >",
-      eFormatterMatchExact, std_string_summary_sp);
-  cpp_category_sp->AddTypeSummary(
-      "std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
-      eFormatterMatchExact, std_string_summary_sp);
-
   cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
                                   cxx11_string_summary_sp);
   cpp_category_sp->AddTypeSummary(
@@ -1418,23 +1441,6 @@ static void 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                                   eFormatterMatchExact,
                                   cxx11_string_summary_sp);
 
-  // making sure we force-pick the summary for printing wstring (_M_p is a
-  // wchar_t*)
-  lldb::TypeSummaryImplSP std_wstring_summary_sp(
-      new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
-
-  cpp_category_sp->AddTypeSummary("std::wstring", eFormatterMatchExact,
-                                  std_wstring_summary_sp);
-  cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t>",
-                                  eFormatterMatchExact, 
std_wstring_summary_sp);
-  cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t,std::char_traits<"
-                                  "wchar_t>,std::allocator<wchar_t> >",
-                                  eFormatterMatchExact, 
std_wstring_summary_sp);
-  cpp_category_sp->AddTypeSummary(
-      "std::basic_string<wchar_t, std::char_traits<wchar_t>, "
-      "std::allocator<wchar_t> >",
-      eFormatterMatchExact, std_wstring_summary_sp);
-
   cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", 
eFormatterMatchExact,
                                   cxx11_wstring_summary_sp);
   cpp_category_sp->AddTypeSummary(
@@ -1629,6 +1635,82 @@ static void 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                 "^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
 }
 
+static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
+  if (!cpp_category_sp)
+    return;
+
+  TypeSummaryImpl::Flags stl_summary_flags;
+  stl_summary_flags.SetCascades(true)
+      .SetSkipPointers(false)
+      .SetSkipReferences(false)
+      .SetDontShowChildren(true)
+      .SetDontShowValue(false)
+      .SetShowMembersOneLiner(false)
+      .SetHideItemNames(false);
+  using StringElementType = StringPrinter::StringElementType;
+
+  RegisterStdStringSummaryProvider(
+      cpp_category_sp, "std::string", "char",
+      TypeSummaryImplSP{
+          (new CXXCascadingSummaryFormat(
+               stl_summary_flags,
+               "MSVC/libstdc++ std::string summary provider"))
+              ->Append(
+                  IsMsvcStdStringType,
+                  CXXFunctionSummaryData{
+                      MsvcStlStringSummaryProvider<StringElementType::ASCII>})
+              // libstdc++ (fallback)
+              ->Append(nullptr, StringSummaryData("${var._M_dataplus._M_p}")),
+      });
+  RegisterStdStringSummaryProvider(
+      cpp_category_sp, "std::wstring", "wchar_t",
+      TypeSummaryImplSP{
+          (new CXXCascadingSummaryFormat(
+               stl_summary_flags,
+               "MSVC/libstdc++ std::wstring summary provider"))
+              ->Append(IsMsvcStdStringType,
+                       CXXFunctionSummaryData{MsvcStlWStringSummaryProvider})
+              // libstdc++: making sure we force-pick the summary for printing
+              // wstring (_M_p is a wchar_t*)
+              ->Append(nullptr, 
StringSummaryData("${var._M_dataplus._M_p%S}")),
+      });
+}
+
+static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
+  if (!cpp_category_sp)
+    return;
+
+  TypeSummaryImpl::Flags stl_summary_flags;
+  stl_summary_flags.SetCascades(true)
+      .SetSkipPointers(false)
+      .SetSkipReferences(false)
+      .SetDontShowChildren(true)
+      .SetDontShowValue(false)
+      .SetShowMembersOneLiner(false)
+      .SetHideItemNames(false);
+
+  using StringElementType = StringPrinter::StringElementType;
+
+  RegisterStdStringSummaryProvider(
+      cpp_category_sp, "std::u8string", "char8_t",
+      std::make_shared<CXXFunctionSummaryFormat>(
+          stl_summary_flags,
+          MsvcStlStringSummaryProvider<StringElementType::UTF8>,
+          "MSVC STL std::u8string summary provider"));
+  RegisterStdStringSummaryProvider(
+      cpp_category_sp, "std::u16string", "char16_t",
+      std::make_shared<CXXFunctionSummaryFormat>(
+          stl_summary_flags,
+          MsvcStlStringSummaryProvider<StringElementType::UTF16>,
+          "MSVC STL std::u16string summary provider"));
+  RegisterStdStringSummaryProvider(
+      cpp_category_sp, "std::u32string", "char32_t",
+      std::make_shared<CXXFunctionSummaryFormat>(
+          stl_summary_flags,
+          MsvcStlStringSummaryProvider<StringElementType::UTF32>,
+          "MSVC STL std::u32string summary provider"));
+}
+
 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
   if (!cpp_category_sp)
     return;
@@ -1743,6 +1825,8 @@ lldb::TypeCategoryImplSP 
CPlusPlusLanguage::GetFormatters() {
       // LLDB prioritizes the last loaded matching formatter.
       LoadLibCxxFormatters(g_category);
       LoadLibStdcppFormatters(g_category);
+      LoadMsvcStlFormatters(g_category);
+      LoadCommonStlFormatters(g_category);
       LoadSystemFormatters(g_category);
     }
   });
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
index fc17b76804d9f..c3d5b7bc1ba26 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
@@ -37,6 +37,8 @@ using StringElementType = StringPrinter::StringElementType;
 static constexpr std::pair<const char *, Format>
 getElementTraits(StringElementType ElemType) {
   switch (ElemType) {
+  case StringElementType::ASCII:
+    return std::make_pair("", lldb::eFormatUnicode8);
   case StringElementType::UTF8:
     return std::make_pair("u8", lldb::eFormatUnicode8);
   case StringElementType::UTF16:
@@ -49,7 +51,8 @@ getElementTraits(StringElementType ElemType) {
 }
 
 template <StringElementType ElemType>
-static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) {
+bool lldb_private::formatters::CharTStringSummaryProvider(ValueObject &valobj,
+                                                          Stream &stream) {
   Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
   if (!valobj_addr.IsValid())
     return false;
@@ -66,6 +69,11 @@ static bool CharStringSummaryProvider(ValueObject &valobj, 
Stream &stream) {
   return true;
 }
 
+// explicit instantiation for ASCII strings
+template bool
+lldb_private::formatters::CharTStringSummaryProvider<StringElementType::ASCII>(
+    ValueObject &, Stream &);
+
 template <StringElementType ElemType>
 static bool CharSummaryProvider(ValueObject &valobj, Stream &stream) {
   DataExtractor data;
@@ -96,17 +104,17 @@ static bool CharSummaryProvider(ValueObject &valobj, 
Stream &stream) {
 
 bool lldb_private::formatters::Char8StringSummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
-  return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
+  return CharTStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
 }
 
 bool lldb_private::formatters::Char16StringSummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
-  return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
+  return CharTStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
 }
 
 bool lldb_private::formatters::Char32StringSummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
-  return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
+  return CharTStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
 }
 
 bool lldb_private::formatters::WCharStringSummaryProvider(
@@ -183,7 +191,7 @@ bool lldb_private::formatters::WCharSummaryProvider(
   if (!wchar_compiler_type)
     return false;
 
-    // Safe to pass nullptr for exe_scope here.
+  // Safe to pass nullptr for exe_scope here.
   std::optional<uint64_t> size =
       llvm::expectedToOptional(wchar_compiler_type.GetBitSize(nullptr));
   if (!size)
@@ -214,3 +222,143 @@ bool lldb_private::formatters::WCharSummaryProvider(
   }
   return true;
 }
+
+template <StringPrinter::StringElementType element_type>
+bool lldb_private::formatters::StdStringSummaryProviderImpl(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options, std::string prefix_token,
+    ValueObjectSP location_sp, uint64_t size) {
+
+  if (size == 0) {
+    stream.PutCString(prefix_token);
+    stream.PutCString("\"\"");
+    return true;
+  }
+
+  if (!location_sp)
+    return false;
+
+  StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
+
+  if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
+    const auto max_size = 
valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
+    if (size > max_size) {
+      size = max_size;
+      options.SetIsTruncated(true);
+    }
+  }
+
+  {
+    DataExtractor extractor;
+    const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
+    if (bytes_read < size)
+      return false;
+
+    options.SetData(std::move(extractor));
+  }
+  options.SetStream(&stream);
+  if (prefix_token.empty())
+    options.SetPrefixToken(nullptr);
+  else
+    options.SetPrefixToken(prefix_token);
+  options.SetQuote('"');
+  options.SetSourceSize(size);
+  options.SetBinaryZeroIsTerminator(false);
+  return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
+}
+
+bool lldb_private::formatters::StdStringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options, std::string prefix_token,
+    lldb::ValueObjectSP location_sp, uint64_t size) {
+  return StdStringSummaryProviderImpl<StringPrinter::StringElementType::ASCII>(
+      valobj, stream, summary_options, prefix_token, location_sp, size);
+}
+
+bool lldb_private::formatters::StdU8StringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options, std::string prefix_token,
+    lldb::ValueObjectSP location_sp, uint64_t size) {
+  return StdStringSummaryProviderImpl<StringPrinter::StringElementType::UTF8>(
+      valobj, stream, summary_options, prefix_token, location_sp, size);
+}
+
+bool lldb_private::formatters::StdU16StringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options, std::string prefix_token,
+    lldb::ValueObjectSP location_sp, uint64_t size) {
+  return StdStringSummaryProviderImpl<StringPrinter::StringElementType::UTF16>(
+      valobj, stream, summary_options, prefix_token, location_sp, size);
+}
+
+bool lldb_private::formatters::StdU32StringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options, std::string prefix_token,
+    lldb::ValueObjectSP location_sp, uint64_t size) {
+  return StdStringSummaryProviderImpl<StringPrinter::StringElementType::UTF32>(
+      valobj, stream, summary_options, prefix_token, location_sp, size);
+}
+
+bool lldb_private::formatters::StdWStringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options, std::string prefix_token,
+    lldb::ValueObjectSP location_sp, uint64_t size) {
+  if (size == 0) {
+    stream.Printf("L\"\"");
+    return true;
+  }
+  if (!location_sp)
+    return false;
+
+  StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
+  if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
+    const auto max_size = 
valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
+    if (size > max_size) {
+      size = max_size;
+      options.SetIsTruncated(true);
+    }
+  }
+
+  DataExtractor extractor;
+  const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
+  if (bytes_read < size)
+    return false;
+
+  // std::wstring::size() is measured in 'characters', not bytes
+  TypeSystemClangSP scratch_ts_sp =
+      ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());
+  if (!scratch_ts_sp)
+    return false;
+
+  auto wchar_t_size =
+      scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
+  if (!wchar_t_size)
+    return false;
+
+  options.SetData(std::move(extractor));
+  options.SetStream(&stream);
+  options.SetPrefixToken("L");
+  options.SetQuote('"');
+  options.SetSourceSize(size);
+  options.SetBinaryZeroIsTerminator(false);
+
+  switch (*wchar_t_size) {
+  case 1:
+    return StringPrinter::ReadBufferAndDumpToStream<
+        lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
+        options);
+    break;
+
+  case 2:
+    return StringPrinter::ReadBufferAndDumpToStream<
+        lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
+        options);
+    break;
+
+  case 4:
+    return StringPrinter::ReadBufferAndDumpToStream<
+        lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
+        options);
+  }
+  return false;
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h 
b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
index a2b606d28cac1..c4e938e89535d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
@@ -10,12 +10,17 @@
 #ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
 #define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
 
+#include "lldb/DataFormatters/StringPrinter.h"
 #include "lldb/DataFormatters/TypeSummary.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/ValueObject/ValueObject.h"
 
 namespace lldb_private {
 namespace formatters {
+
+template <StringPrinter::StringElementType element_type>
+bool CharTStringSummaryProvider(ValueObject &valobj, Stream &stream);
+
 bool Char8StringSummaryProvider(ValueObject &valobj, Stream &stream,
                                 const TypeSummaryOptions &options); // char8_t*
 
@@ -43,6 +48,36 @@ bool Char32SummaryProvider(ValueObject &valobj, Stream 
&stream,
 bool WCharSummaryProvider(ValueObject &valobj, Stream &stream,
                           const TypeSummaryOptions &options); // wchar_t
 
+template <StringPrinter::StringElementType element_type>
+bool StdStringSummaryProviderImpl(ValueObject &valobj, Stream &stream,
+                                  const TypeSummaryOptions &summary_options,
+                                  std::string prefix_token,
+                                  lldb::ValueObjectSP location_sp,
+                                  uint64_t size);
+
+bool StdStringSummaryProvider(ValueObject &valobj, Stream &stream,
+                              const TypeSummaryOptions &summary_options,
+                              std::string prefix_token,
+                              lldb::ValueObjectSP location_sp, uint64_t size);
+bool StdU8StringSummaryProvider(ValueObject &valobj, Stream &stream,
+                                const TypeSummaryOptions &summary_options,
+                                std::string prefix_token,
+                                lldb::ValueObjectSP location_sp, uint64_t 
size);
+bool StdU16StringSummaryProvider(ValueObject &valobj, Stream &stream,
+                                 const TypeSummaryOptions &summary_options,
+                                 std::string prefix_token,
+                                 lldb::ValueObjectSP location_sp,
+                                 uint64_t size);
+bool StdU32StringSummaryProvider(ValueObject &valobj, Stream &stream,
+                                 const TypeSummaryOptions &summary_options,
+                                 std::string prefix_token,
+                                 lldb::ValueObjectSP location_sp,
+                                 uint64_t size);
+bool StdWStringSummaryProvider(ValueObject &valobj, Stream &stream,
+                               const TypeSummaryOptions &summary_options,
+                               std::string prefix_token,
+                               lldb::ValueObjectSP location_sp, uint64_t size);
+
 } // namespace formatters
 } // namespace lldb_private
 
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 358cf7d78fa21..f640bc8f5ab69 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -24,6 +24,7 @@
 #include "lldb/ValueObject/ValueObject.h"
 #include "lldb/ValueObject/ValueObjectConstResult.h"
 
+#include "Plugins/Language/CPlusPlus/CxxStringTypes.h"
 #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/lldb-enumerations.h"
@@ -535,70 +536,6 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
   return std::make_pair(size, location_sp);
 }
 
-static bool
-LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream,
-                             const TypeSummaryOptions &summary_options,
-                             ValueObjectSP location_sp, size_t size) {
-  if (size == 0) {
-    stream.Printf("L\"\"");
-    return true;
-  }
-  if (!location_sp)
-    return false;
-
-  StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
-  if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
-    const auto max_size = 
valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
-    if (size > max_size) {
-      size = max_size;
-      options.SetIsTruncated(true);
-    }
-  }
-
-  DataExtractor extractor;
-  const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
-  if (bytes_read < size)
-    return false;
-
-  // std::wstring::size() is measured in 'characters', not bytes
-  TypeSystemClangSP scratch_ts_sp =
-      ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());
-  if (!scratch_ts_sp)
-    return false;
-
-  auto wchar_t_size =
-      scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
-  if (!wchar_t_size)
-    return false;
-
-  options.SetData(std::move(extractor));
-  options.SetStream(&stream);
-  options.SetPrefixToken("L");
-  options.SetQuote('"');
-  options.SetSourceSize(size);
-  options.SetBinaryZeroIsTerminator(false);
-
-  switch (*wchar_t_size) {
-  case 1:
-    return StringPrinter::ReadBufferAndDumpToStream<
-        lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
-        options);
-    break;
-
-  case 2:
-    return StringPrinter::ReadBufferAndDumpToStream<
-        lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
-        options);
-    break;
-
-  case 4:
-    return StringPrinter::ReadBufferAndDumpToStream<
-        lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
-        options);
-  }
-  return false;
-}
-
 bool lldb_private::formatters::LibcxxWStringSummaryProvider(
     ValueObject &valobj, Stream &stream,
     const TypeSummaryOptions &summary_options) {
@@ -609,52 +546,8 @@ bool 
lldb_private::formatters::LibcxxWStringSummaryProvider(
   ValueObjectSP location_sp;
   std::tie(size, location_sp) = *string_info;
 
-  return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
-                                        location_sp, size);
-}
-
-template <StringPrinter::StringElementType element_type>
-static bool
-LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
-                            const TypeSummaryOptions &summary_options,
-                            std::string prefix_token, ValueObjectSP 
location_sp,
-                            uint64_t size) {
-
-  if (size == 0) {
-    stream.Printf("\"\"");
-    return true;
-  }
-
-  if (!location_sp)
-    return false;
-
-  StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
-
-  if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
-    const auto max_size = 
valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
-    if (size > max_size) {
-      size = max_size;
-      options.SetIsTruncated(true);
-    }
-  }
-
-  {
-    DataExtractor extractor;
-    const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
-    if (bytes_read < size)
-      return false;
-
-    options.SetData(std::move(extractor));
-  }
-  options.SetStream(&stream);
-  if (prefix_token.empty())
-    options.SetPrefixToken(nullptr);
-  else
-    options.SetPrefixToken(prefix_token);
-  options.SetQuote('"');
-  options.SetSourceSize(size);
-  options.SetBinaryZeroIsTerminator(false);
-  return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
+  return lldb_private::formatters::StdWStringSummaryProvider(
+      valobj, stream, summary_options, "L", location_sp, size);
 }
 
 template <StringPrinter::StringElementType element_type>
@@ -669,7 +562,7 @@ LibcxxStringSummaryProvider(ValueObject &valobj, Stream 
&stream,
   ValueObjectSP location_sp;
   std::tie(size, location_sp) = *string_info;
 
-  return LibcxxStringSummaryProvider<element_type>(
+  return StdStringSummaryProviderImpl<element_type>(
       valobj, stream, summary_options, prefix_token, location_sp, size);
 }
 template <StringPrinter::StringElementType element_type>
@@ -742,7 +635,7 @@ static bool formatStringViewImpl(ValueObject &valobj, 
Stream &stream,
     return true;
   }
 
-  return LibcxxStringSummaryProvider<element_type>(
+  return StdStringSummaryProviderImpl<element_type>(
       valobj, stream, summary_options, prefix_token, dataobj, size);
 }
 
@@ -781,8 +674,8 @@ bool 
lldb_private::formatters::LibcxxWStringViewSummaryProvider(
     return true;
   }
 
-  return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
-                                        dataobj, size);
+  return StdWStringSummaryProvider(valobj, stream, summary_options, "L",
+                                   dataobj, size);
 }
 
 static bool
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
new file mode 100644
index 0000000000000..0632ced09e5ab
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
@@ -0,0 +1,140 @@
+//===-- MsvcStl.cpp 
-------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MsvcStl.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FormatEntity.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/ValueObject/ValueObject.h"
+
+#include "Plugins/Language/CPlusPlus/CxxStringTypes.h"
+
+#include "lldb/lldb-forward.h"
+#include <optional>
+#include <tuple>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+using StringElementType = StringPrinter::StringElementType;
+
+static ValueObjectSP ExtractMsvcStlStringData(ValueObject &valobj) {
+  auto pair = valobj.GetChildMemberWithName("_Mypair");
+  if (!pair)
+    return nullptr;
+  return pair->GetChildMemberWithName("_Myval2");
+}
+
+/// Determine the size in bytes of \p valobj (a MSVC STL std::string object) 
and
+/// extract its data payload. Return the size + payload pair.
+static std::optional<std::pair<uint64_t, ValueObjectSP>>
+ExtractMsvcStlStringInfo(ValueObject &valobj, uint64_t element_size) {
+  ValueObjectSP valobj_pair_sp = ExtractMsvcStlStringData(valobj);
+  if (!valobj_pair_sp || !valobj_pair_sp->GetError().Success())
+    return {};
+
+  ValueObjectSP size_sp = valobj_pair_sp->GetChildMemberWithName("_Mysize");
+  ValueObjectSP capacity_sp = valobj_pair_sp->GetChildMemberWithName("_Myres");
+  ValueObjectSP bx_sp = valobj_pair_sp->GetChildMemberWithName("_Bx");
+  if (!size_sp || !capacity_sp || !bx_sp)
+    return {};
+
+  bool success = false;
+  uint64_t size = size_sp->GetValueAsUnsigned(0, &success);
+  if (!success)
+    return {};
+  uint64_t capacity = capacity_sp->GetValueAsUnsigned(0, &success);
+  if (!success)
+    return {};
+
+  size_t bufSize = std::max<size_t>(16 / element_size, 1);
+  bool isShortString = capacity < bufSize;
+
+  if (isShortString) {
+    ValueObjectSP buf_sp = bx_sp->GetChildMemberWithName("_Buf");
+    if (buf_sp)
+      return std::make_pair(size, buf_sp);
+    return {};
+  }
+  ValueObjectSP ptr_sp = bx_sp->GetChildMemberWithName("_Ptr");
+  if (ptr_sp)
+    return std::make_pair(size, ptr_sp);
+  return {};
+}
+
+template <StringPrinter::StringElementType element_type>
+static bool
+MsvcStlStringSummaryProviderImpl(ValueObject &valobj, Stream &stream,
+                                 const TypeSummaryOptions &summary_options,
+                                 std::string prefix_token) {
+  auto string_info = ExtractMsvcStlStringInfo(
+      valobj, StringPrinter::ElementByteSize<element_type>());
+  if (!string_info)
+    return false;
+  uint64_t size;
+  ValueObjectSP location_sp;
+  std::tie(size, location_sp) = *string_info;
+
+  return StdStringSummaryProviderImpl<element_type>(
+      valobj, stream, summary_options, prefix_token, location_sp, size);
+}
+template <StringPrinter::StringElementType element_type>
+static bool formatStringImpl(ValueObject &valobj, Stream &stream,
+                             const TypeSummaryOptions &summary_options,
+                             std::string prefix_token) {
+  StreamString scratch_stream;
+  const bool success = MsvcStlStringSummaryProviderImpl<element_type>(
+      valobj, scratch_stream, summary_options, prefix_token);
+  if (success)
+    stream << scratch_stream.GetData();
+  else
+    stream << "Summary Unavailable";
+  return true;
+}
+
+bool lldb_private::formatters::MsvcStlWStringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &summary_options) {
+  return formatStringImpl<StringElementType::UTF16>(valobj, stream,
+                                                    summary_options, "L");
+}
+
+template <>
+bool lldb_private::formatters::MsvcStlStringSummaryProvider<
+    StringElementType::ASCII>(ValueObject &valobj, Stream &stream,
+                              const TypeSummaryOptions &summary_options) {
+  return MsvcStlStringSummaryProviderImpl<StringElementType::ASCII>(
+      valobj, stream, summary_options, {});
+}
+template <>
+bool lldb_private::formatters::MsvcStlStringSummaryProvider<
+    StringElementType::UTF8>(ValueObject &valobj, Stream &stream,
+                             const TypeSummaryOptions &summary_options) {
+  return MsvcStlStringSummaryProviderImpl<StringElementType::UTF8>(
+      valobj, stream, summary_options, "u8");
+}
+template <>
+bool lldb_private::formatters::MsvcStlStringSummaryProvider<
+    StringElementType::UTF16>(ValueObject &valobj, Stream &stream,
+                              const TypeSummaryOptions &summary_options) {
+  return MsvcStlStringSummaryProviderImpl<StringElementType::UTF16>(
+      valobj, stream, summary_options, "u");
+}
+template <>
+bool lldb_private::formatters::MsvcStlStringSummaryProvider<
+    StringElementType::UTF32>(ValueObject &valobj, Stream &stream,
+                              const TypeSummaryOptions &summary_options) {
+  return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>(
+      valobj, stream, summary_options, "U");
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h 
b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
new file mode 100644
index 0000000000000..c8f7b4027b94c
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
@@ -0,0 +1,33 @@
+//===-- MsvcStl.h -----------------------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCSTL_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCSTL_H
+
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/ValueObject/ValueObject.h"
+
+namespace lldb_private {
+namespace formatters {
+
+template <StringPrinter::StringElementType element_type>
+bool MsvcStlStringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions
+        &summary_options); // VC 2015+ std::string,u8string,u16string,u32string
+
+bool MsvcStlWStringSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &options); // VC 2015+ std::wstring
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
index 5c5cf4ca16b98..32764629d65a7 100644
--- 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
@@ -65,11 +65,9 @@ def cleanup():
                 '(%s::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ 
ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"'
                 % ns,
                 '(%s::u16string) u16_string = u"ß水氶"' % ns,
-                # FIXME: This should have a 'u' prefix.
-                '(%s::u16string) u16_empty = ""' % ns,
+                '(%s::u16string) u16_empty = u""' % ns,
                 '(%s::u32string) u32_string = U"🍄🍅🍆🍌"' % ns,
-                # FIXME: This should have a 'U' prefix.
-                '(%s::u32string) u32_empty = ""' % ns,
+                '(%s::u32string) u32_empty = U""' % ns,
                 "(%s::string *) null_str = nullptr" % ns,
             ],
         )
@@ -123,7 +121,7 @@ def cleanup():
                 % ns,
                 '(%s::u16string) u16_string = u"ß水氶"' % ns,
                 '(%s::u32string) u32_string = U"🍄🍅🍆🍌"' % ns,
-                '(%s::u32string) u32_empty = ""' % ns,
+                '(%s::u32string) u32_empty = U""' % ns,
                 "(%s::string *) null_str = nullptr" % ns,
             ],
         )
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string_view/TestDataFormatterLibcxxStringView.py
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string_view/TestDataFormatterLibcxxStringView.py
index f8fc8ae66405b..3883395f23924 100644
--- 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string_view/TestDataFormatterLibcxxStringView.py
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string_view/TestDataFormatterLibcxxStringView.py
@@ -81,11 +81,11 @@ def cleanup():
             summary='L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
         )
         self.expect_var_path("u16_string", type="std::u16string_view", 
summary='u"ß水氶"')
-        self.expect_var_path("u16_empty", type="std::u16string_view", 
summary='""')
+        self.expect_var_path("u16_empty", type="std::u16string_view", 
summary='u""')
         self.expect_var_path(
             "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
         )
-        self.expect_var_path("u32_empty", type="std::u32string_view", 
summary='""')
+        self.expect_var_path("u32_empty", type="std::u32string_view", 
summary='U""')
         self.expect_var_path(
             "oops", type="std::string_view", summary='"Hellooo World\\n"'
         )
@@ -145,11 +145,11 @@ def cleanup():
             summary='L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
         )
         self.expect_var_path("u16_string", type="std::u16string_view", 
summary='u"ß水氶"')
-        self.expect_var_path("u16_empty", type="std::u16string_view", 
summary='""')
+        self.expect_var_path("u16_empty", type="std::u16string_view", 
summary='u""')
         self.expect_var_path(
             "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
         )
-        self.expect_var_path("u32_empty", type="std::u32string_view", 
summary='""')
+        self.expect_var_path("u32_empty", type="std::u32string_view", 
summary='U""')
 
         self.runCmd("cont")
         self.expect(
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/Makefile
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/Makefile
new file mode 100644
index 0000000000000..f64db8d081fbe
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+
+CXXFLAGS_EXTRAS := -std=c++14 -O0
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/TestDataFormatterStdString.py
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/TestDataFormatterStdString.py
new file mode 100644
index 0000000000000..911313e0d7f3a
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/TestDataFormatterStdString.py
@@ -0,0 +1,117 @@
+# coding=utf8
+"""
+Test std::*string summaries with MSVC's STL.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class MsvcStlStringDataFormatterTestCase(TestBase):
+    @add_test_categories(["msvcstl"])
+    def test_with_run_command(self):
+        """Test that that file and class static variables display correctly."""
+        self.build()
+
+        main_spec = lldb.SBFileSpec("main.cpp")
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "Set break point at this line.", main_spec
+        )
+        frame = thread.frames[0]
+
+        # This is the function to remove the custom formats in order to have a
+        # clean slate for the next test case.
+        def cleanup():
+            self.runCmd("type format clear", check=False)
+            self.runCmd("type summary clear", check=False)
+            self.runCmd("type filter clear", check=False)
+            self.runCmd("type synth clear", check=False)
+
+        # Execute the cleanup function during test case tear down.
+        self.addTearDownHook(cleanup)
+
+        self.expect(
+            "frame variable",
+            substrs=[
+                '(std::wstring) wempty = L""',
+                '(std::wstring) s = L"hello world! מזל טוב!"',
+                '(std::wstring) S = L"!!!!"',
+                "(const wchar_t *) mazeltov = 0x",
+                'L"מזל טוב"',
+                '(std::string) empty = ""',
+                '(std::string) q = "hello world"',
+                '(std::string) Q = "quite a long std::strin with lots of info 
inside it"',
+                '(std::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
+                '(std::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ 
ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
+                '(std::u16string) u16_string = u"ß水氶"',
+                '(std::u16string) u16_empty = u""',
+                '(std::u32string) u32_string = U"🍄🍅🍆🍌"',
+                '(std::u32string) u32_empty = U""',
+                "(std::string *) null_str = nullptr",
+            ],
+        )
+
+        thread.StepOver()
+
+        TheVeryLongOne = frame.FindVariable("TheVeryLongOne")
+        summaryOptions = lldb.SBTypeSummaryOptions()
+        summaryOptions.SetCapping(lldb.eTypeSummaryUncapped)
+        uncappedSummaryStream = lldb.SBStream()
+        TheVeryLongOne.GetSummary(uncappedSummaryStream, summaryOptions)
+        uncappedSummary = uncappedSummaryStream.GetData()
+        self.assertGreater(
+            uncappedSummary.find("someText"),
+            0,
+            "uncappedSummary does not include the full string",
+        )
+        summaryOptions.SetCapping(lldb.eTypeSummaryCapped)
+        cappedSummaryStream = lldb.SBStream()
+        TheVeryLongOne.GetSummary(cappedSummaryStream, summaryOptions)
+        cappedSummary = cappedSummaryStream.GetData()
+        self.assertLessEqual(
+            cappedSummary.find("someText"), 0, "cappedSummary includes the 
full string"
+        )
+
+        self.expect_expr(
+            "s", result_type="std::wstring", result_summary='L"hello world! 
מזל טוב!"'
+        )
+
+        self.expect_expr("q", result_type="std::string", 
result_summary='"hello world"')
+
+        self.expect_expr(
+            "Q",
+            result_type="std::string",
+            result_summary='"quite a long std::strin with lots of info inside 
it"',
+        )
+
+        self.expect(
+            "frame variable",
+            substrs=[
+                '(std::wstring) S = L"!!!!!"',
+                "(const wchar_t *) mazeltov = 0x",
+                'L"מזל טוב"',
+                '(std::string) q = "hello world"',
+                '(std::string) Q = "quite a long std::strin with lots of info 
inside it"',
+                '(std::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
+                '(std::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ 
ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
+                '(std::u16string) u16_string = u"ß水氶"',
+                '(std::u32string) u32_string = U"🍄🍅🍆🍌"',
+                '(std::u32string) u32_empty = U""',
+                "(std::string *) null_str = nullptr",
+            ],
+        )
+
+        # Finally, make sure that if the string is not readable, we give an 
error:
+        bkpt_2 = target.BreakpointCreateBySourceRegex(
+            "Break here to look at bad string", main_spec
+        )
+        self.assertEqual(bkpt_2.GetNumLocations(), 1, "Got one location")
+        threads = lldbutil.continue_to_breakpoint(process, bkpt_2)
+        self.assertEqual(len(threads), 1, "Stopped at second breakpoint")
+        frame = threads[0].frames[0]
+        var = frame.FindVariable("in_str")
+        self.assertTrue(var.GetError().Success(), "Made variable")
+        self.assertIsNone(var.GetSummary())
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/main.cpp
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/main.cpp
new file mode 100644
index 0000000000000..6f8dbd9c51b10
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/string/main.cpp
@@ -0,0 +1,38 @@
+#include <stdint.h>
+
+#include <string>
+
+#ifndef _MSVC_STL_VERSION
+// this is more of a sanity check that the categories work as expected
+#error Not using MSVC STL
+#endif
+
+static size_t touch_string(std::string &in_str) {
+  return in_str.size(); // Break here to look at bad string
+}
+
+int main() {
+  std::wstring wempty(L"");
+  std::wstring s(L"hello world! מזל טוב!");
+  std::wstring S(L"!!!!");
+  const wchar_t *mazeltov = L"מזל טוב";
+  std::string empty("");
+  std::string q("hello world");
+  std::string Q("quite a long std::strin with lots of info inside it");
+  // clang-format off
+  std::string 
TheVeryLongOne("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890someText1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+  // clang-format on
+  std::string IHaveEmbeddedZeros("a\0b\0c\0d", 7);
+  std::wstring IHaveEmbeddedZerosToo(
+      L"hello world!\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監", 38);
+  std::u16string u16_string(u"ß水氶");
+  std::u16string u16_empty(u"");
+  std::u32string u32_string(U"🍄🍅🍆🍌");
+  std::u32string u32_empty(U"");
+  std::string *null_str = nullptr;
+
+  S.assign(L"!!!!!"); // Set break point at this line.
+  std::string *not_a_string = (std::string *)0x0;
+  touch_string(*not_a_string);
+  return 0;
+}
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/Makefile
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/Makefile
new file mode 100644
index 0000000000000..58558e6e15f78
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+
+CXXFLAGS_EXTRAS := -std=c++20 -O0
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/TestDataFormatterStdU8String.py
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/TestDataFormatterStdU8String.py
new file mode 100644
index 0000000000000..9864cc1bae8ac
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/TestDataFormatterStdU8String.py
@@ -0,0 +1,31 @@
+# coding=utf8
+"""
+Test std::u8string summary with MSVC's STL.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class MsvcStlU8StringDataFormatterTestCase(TestBase):
+    @add_test_categories(["msvcstl"])
+    def test_with_run_command(self):
+        """Test that that file and class static variables display correctly."""
+        self.build()
+
+        lldbutil.run_to_source_breakpoint(
+            self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect(
+            "frame variable",
+            substrs=[
+                '(std::u8string) u8_string_small = u8"🍄"',
+                '(std::u8string) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
+                '(std::u8string) u8_empty = u8""',
+                '(std::u8string) u8_text = u8"ABC"',
+            ],
+        )
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/main.cpp
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/main.cpp
new file mode 100644
index 0000000000000..e01af9fa08e7e
--- /dev/null
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvcstl/u8string/main.cpp
@@ -0,0 +1,14 @@
+#include <string>
+
+#ifndef _MSVC_STL_VERSION
+// this is more of a sanity check that the categories work as expected
+#error Not using MSVC STL
+#endif
+
+int main() {
+  std::u8string u8_string_small(u8"🍄");
+  std::u8string u8_string(u8"❤️👍📄📁😃🧑‍🌾");
+  std::u8string u8_empty(u8"");
+  std::u8string u8_text(u8"ABC");
+  u8_text.assign(u8"ABCd"); // Set break point at this line.
+}

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to