Add go data formatters.

Differential Revision: http://reviews.llvm.org/D13878

llvm-svn: 252109
diff --git a/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp b/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp
new file mode 100644
index 0000000..f80a153
--- /dev/null
+++ b/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp
@@ -0,0 +1,174 @@
+//===-- GoFormatterFunctions.cpp---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "GoFormatterFunctions.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace
+{
+class GoSliceSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+{
+  public:
+    GoSliceSyntheticFrontEnd(ValueObject &valobj)
+        : SyntheticChildrenFrontEnd(valobj)
+    {
+        Update();
+    }
+
+    ~GoSliceSyntheticFrontEnd() override = default;
+
+    size_t
+    CalculateNumChildren() override
+    {
+        return m_len;
+    }
+
+    lldb::ValueObjectSP
+    GetChildAtIndex(size_t idx) override
+    {
+        if (idx < m_len)
+        {
+            ValueObjectSP &cached = m_children[idx];
+            if (!cached)
+            {
+                StreamString idx_name;
+                idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+                lldb::addr_t object_at_idx = m_base_data_address;
+                object_at_idx += idx * m_type.GetByteSize(nullptr);
+                cached = CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx,
+                                                      m_backend.GetExecutionContextRef(), m_type);
+            }
+            return cached;
+        }
+        return ValueObjectSP();
+    }
+
+    bool
+    Update() override
+    {
+        size_t old_count = m_len;
+
+        ConstString array_const_str("array");
+        ValueObjectSP array_sp = m_backend.GetChildMemberWithName(array_const_str, true);
+        if (!array_sp)
+        {
+            m_children.clear();
+            return old_count == 0;
+        }
+        m_type = array_sp->GetCompilerType().GetPointeeType();
+        m_base_data_address = array_sp->GetPointerValue();
+
+        ConstString len_const_str("len");
+        ValueObjectSP len_sp = m_backend.GetChildMemberWithName(len_const_str, true);
+        if (len_sp)
+        {
+            m_len = len_sp->GetValueAsUnsigned(0);
+            m_children.clear();
+        }
+
+        return old_count == m_len;
+    }
+
+    bool
+    MightHaveChildren() override
+    {
+        return true;
+    }
+
+    size_t
+    GetIndexOfChildWithName(const ConstString &name) override
+    {
+        return ExtractIndexFromString(name.AsCString());
+    }
+
+  private:
+    CompilerType m_type;
+    lldb::addr_t m_base_data_address;
+    size_t m_len;
+    std::map<size_t, lldb::ValueObjectSP> m_children;
+};
+
+} // anonymous namespace
+
+bool
+lldb_private::formatters::GoStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts)
+{
+    ProcessSP process_sp = valobj.GetProcessSP();
+    if (!process_sp)
+        return false;
+
+    if (valobj.IsPointerType())
+    {
+        Error err;
+        ValueObjectSP deref = valobj.Dereference(err);
+        if (!err.Success())
+            return false;
+        return GoStringSummaryProvider(*deref, stream, opts);
+    }
+
+    ConstString str_name("str");
+    ConstString len_name("len");
+
+    ValueObjectSP data_sp = valobj.GetChildMemberWithName(str_name, true);
+    ValueObjectSP len_sp = valobj.GetChildMemberWithName(len_name, true);
+    if (!data_sp || !len_sp)
+        return false;
+    bool success;
+    lldb::addr_t valobj_addr = data_sp->GetValueAsUnsigned(0, &success);
+
+    if (!success)
+        return false;
+
+    uint64_t length = len_sp->GetValueAsUnsigned(0);
+    if (length == 0)
+    {
+        stream.Printf("\"\"");
+        return true;
+    }
+
+    StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
+    options.SetLocation(valobj_addr);
+    options.SetProcessSP(process_sp);
+    options.SetStream(&stream);
+    options.SetSourceSize(length);
+    options.SetNeedsZeroTermination(false);
+    options.SetLanguage(eLanguageTypeGo);
+
+    if (!StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options))
+    {
+        stream.Printf("Summary Unavailable");
+        return true;
+    }
+
+    return true;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::GoSliceSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp)
+{
+    if (!valobj_sp)
+        return nullptr;
+
+    lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+    if (!process_sp)
+        return NULL;
+    return new GoSliceSyntheticFrontEnd(*valobj_sp);
+}