Add go data formatters.

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

llvm-svn: 252109
diff --git a/lldb/source/Plugins/Language/CMakeLists.txt b/lldb/source/Plugins/Language/CMakeLists.txt
index 871c99e..60b3da2 100644
--- a/lldb/source/Plugins/Language/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_subdirectory(CPlusPlus)
+add_subdirectory(Go)
 add_subdirectory(ObjC)
 add_subdirectory(ObjCPlusPlus)
diff --git a/lldb/source/Plugins/Language/Go/CMakeLists.txt b/lldb/source/Plugins/Language/Go/CMakeLists.txt
new file mode 100644
index 0000000..f3a9c12
--- /dev/null
+++ b/lldb/source/Plugins/Language/Go/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lldb_library(lldbPluginGoLanguage
+  GoLanguage.cpp
+  GoFormatterFunctions.cpp
+)
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);
+}
diff --git a/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h b/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h
new file mode 100644
index 0000000..ae1eda0
--- /dev/null
+++ b/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h
@@ -0,0 +1,43 @@
+//===-- GoFormatterFunctions.h-----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GoFormatterFunctions_h_
+#define liblldb_GoFormatterFunctions_h_
+
+// C Includes
+#include <stdint.h>
+#include <time.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "clang/AST/ASTContext.h"
+
+// Project includes
+#include "lldb/lldb-forward.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+namespace lldb_private
+{
+namespace formatters
+{
+
+bool GoStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
+
+SyntheticChildrenFrontEnd *GoSliceSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // liblldb_GoFormatterFunctions_h_
diff --git a/lldb/source/Plugins/Language/Go/GoLanguage.cpp b/lldb/source/Plugins/Language/Go/GoLanguage.cpp
new file mode 100644
index 0000000..ed010ff
--- /dev/null
+++ b/lldb/source/Plugins/Language/Go/GoLanguage.cpp
@@ -0,0 +1,146 @@
+//===-- GoLanguage.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
+#include <string.h>
+// C++ Includes
+#include <functional>
+#include <mutex>
+
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "GoLanguage.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Symbol/GoASTContext.h"
+#include "Plugins/Language/Go/GoFormatterFunctions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+void
+GoLanguage::Initialize()
+{
+    PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language", CreateInstance);
+}
+
+void
+GoLanguage::Terminate()
+{
+    PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString
+GoLanguage::GetPluginNameStatic()
+{
+    static ConstString g_name("Go");
+    return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+GoLanguage::GetPluginName()
+{
+    return GetPluginNameStatic();
+}
+
+uint32_t
+GoLanguage::GetPluginVersion()
+{
+    return 1;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+Language *
+GoLanguage::CreateInstance(lldb::LanguageType language)
+{
+    if (language == eLanguageTypeGo)
+        return new GoLanguage();
+    return nullptr;
+}
+
+HardcodedFormatters::HardcodedSummaryFinder
+GoLanguage::GetHardcodedSummaries()
+{
+    static std::once_flag g_initialize;
+    static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
+
+    std::call_once(g_initialize, []() -> void
+                   {
+                       g_formatters.push_back(
+                           [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
+                              FormatManager &) -> TypeSummaryImpl::SharedPointer
+                           {
+                               static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(
+                                   TypeSummaryImpl::Flags().SetDontShowChildren(true),
+                                   lldb_private::formatters::GoStringSummaryProvider, "Go string summary provider"));
+                               if (GoASTContext::IsGoString(valobj.GetCompilerType()))
+                               {
+                                   return formatter_sp;
+                               }
+                               if (GoASTContext::IsGoString(valobj.GetCompilerType().GetPointeeType()))
+                               {
+                                   return formatter_sp;
+                               }
+                               return nullptr;
+                           });
+                       g_formatters.push_back(
+                           [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
+                              FormatManager &) -> TypeSummaryImpl::SharedPointer
+                           {
+                               static lldb::TypeSummaryImplSP formatter_sp(
+                                   new StringSummaryFormat(TypeSummaryImpl::Flags().SetHideItemNames(true),
+                                                           "(len ${var.len}, cap ${var.cap})"));
+                               if (GoASTContext::IsGoSlice(valobj.GetCompilerType()))
+                               {
+                                   return formatter_sp;
+                               }
+                               if (GoASTContext::IsGoSlice(valobj.GetCompilerType().GetPointeeType()))
+                               {
+                                   return formatter_sp;
+                               }
+                               return nullptr;
+                           });
+                   });
+    return g_formatters;
+}
+
+HardcodedFormatters::HardcodedSyntheticFinder
+GoLanguage::GetHardcodedSynthetics()
+{
+    static std::once_flag g_initialize;
+    static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
+
+    std::call_once(g_initialize, []() -> void
+                   {
+                       g_formatters.push_back(
+                           [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
+                              FormatManager &fmt_mgr) -> SyntheticChildren::SharedPointer
+                           {
+                               static CXXSyntheticChildren::SharedPointer formatter_sp(
+                                   new CXXSyntheticChildren(SyntheticChildren::Flags(), "slice synthetic children",
+                                                            lldb_private::formatters::GoSliceSyntheticFrontEndCreator));
+                               if (GoASTContext::IsGoSlice(valobj.GetCompilerType()))
+                               {
+                                   return formatter_sp;
+                               }
+                               return nullptr;
+                           });
+                   });
+
+    return g_formatters;
+}
diff --git a/lldb/source/Plugins/Language/Go/GoLanguage.h b/lldb/source/Plugins/Language/Go/GoLanguage.h
new file mode 100644
index 0000000..67dd04c
--- /dev/null
+++ b/lldb/source/Plugins/Language/Go/GoLanguage.h
@@ -0,0 +1,66 @@
+//===-- GoLanguage.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GoLanguage_h_
+#define liblldb_GoLanguage_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Target/Language.h"
+
+namespace lldb_private
+{
+
+class GoLanguage : public Language
+{
+  public:
+    GoLanguage() = default;
+
+    ~GoLanguage() override = default;
+
+    lldb::LanguageType
+    GetLanguageType() const override
+    {
+        return lldb::eLanguageTypeGo;
+    }
+
+    HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override;
+
+    HardcodedFormatters::HardcodedSyntheticFinder GetHardcodedSynthetics() override;
+
+    //------------------------------------------------------------------
+    // Static Functions
+    //------------------------------------------------------------------
+    static void Initialize();
+
+    static void Terminate();
+
+    static lldb_private::Language *CreateInstance(lldb::LanguageType language);
+
+    static lldb_private::ConstString GetPluginNameStatic();
+
+    //------------------------------------------------------------------
+    // PluginInterface protocol
+    //------------------------------------------------------------------
+    ConstString GetPluginName() override;
+
+    uint32_t GetPluginVersion() override;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_GoLanguage_h_
diff --git a/lldb/source/Plugins/Language/Go/Makefile b/lldb/source/Plugins/Language/Go/Makefile
new file mode 100644
index 0000000..3ea09f6
--- /dev/null
+++ b/lldb/source/Plugins/Language/Go/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Language/Go -------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginGoLanguage
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile