Add support for language plugins to provide data formatters
Historically, data formatters all exist in a global repository (the category map)
On top of that, some formatters can be "hardcoded" when the conditions under which they apply are not expressible as a typename (or typename regex)
This change paves the way to move formatters into per-language buckets such that the C++ plugin is responsible for ownership of the C++ formatters, and so on
The advantages of this are:
a) language formatters only get created when they might apply
b) formatters for a language are clearly owned by the matching language plugin
The current model is one of static instantiation, that is a language knows the full set of formatters it vends and that is only asked-for once, and then handed off to the FormatManager
In a future revision it might be interesting to add similar ability to the language runtimes, and monitor for certain shared library events to add even more library-specific formatters
No formatters are moved as part of this change, so practically speaking this is NFC
llvm-svn: 246515
diff --git a/lldb/source/DataFormatters/CMakeLists.txt b/lldb/source/DataFormatters/CMakeLists.txt
index ad29369..691190a 100644
--- a/lldb/source/DataFormatters/CMakeLists.txt
+++ b/lldb/source/DataFormatters/CMakeLists.txt
@@ -9,6 +9,7 @@
FormatCache.cpp
FormatClasses.cpp
FormatManager.cpp
+ LanguageCategory.cpp
LibCxx.cpp
LibCxxInitializerList.cpp
LibCxxList.cpp
diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp
index e41d341..52209ca 100644
--- a/lldb/source/DataFormatters/FormatManager.cpp
+++ b/lldb/source/DataFormatters/FormatManager.cpp
@@ -16,10 +16,13 @@
#include "lldb/Core/Debugger.h"
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
+#include "lldb/DataFormatters/LanguageCategory.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "llvm/ADT/STLExtras.h"
+#include <initializer_list>
+
using namespace lldb;
using namespace lldb_private;
@@ -472,6 +475,20 @@
return validator_chosen_sp;
}
+void
+FormatManager::LoopThroughCategories (CategoryCallback callback, void* param)
+{
+ m_categories_map.LoopThrough(callback, param);
+ for (const auto& entry : m_language_categories_map)
+ {
+ if (auto category_sp = entry.second->GetCategory())
+ {
+ if (!callback(param, category_sp))
+ break;
+ }
+ }
+}
+
lldb::TypeCategoryImplSP
FormatManager::GetCategory (const ConstString& category_name,
bool can_create)
@@ -596,8 +613,8 @@
}
ConstString
-GetTypeForCache (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+FormatManager::GetTypeForCache (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
{
if (use_dynamic == lldb::eNoDynamicValues)
{
@@ -618,6 +635,28 @@
return ConstString();
}
+static std::initializer_list<lldb::LanguageType>
+GetCandidateLanguages (ValueObject& valobj)
+{
+ lldb::LanguageType lang_type = valobj.GetObjectRuntimeLanguage();
+ switch (lang_type)
+ {
+ default:
+ return {lang_type};
+ }
+}
+
+LanguageCategory*
+FormatManager::GetCategoryForLanguage (lldb::LanguageType lang_type)
+{
+ auto iter = m_language_categories_map.find(lang_type), end = m_language_categories_map.end();
+ if (iter != end)
+ return iter->second.get();
+ LanguageCategory* lang_category = new LanguageCategory(lang_type);
+ m_language_categories_map[lang_type] = LanguageCategory::UniquePointer(lang_category);
+ return lang_category;
+}
+
lldb::TypeFormatImplSP
FormatManager::GetHardcodedFormat (ValueObject& valobj,
lldb::DynamicValueType use_dynamic)
@@ -655,7 +694,29 @@
if (log)
log->Printf("[FormatManager::GetFormat] Cache search failed. Going normal route");
}
- retval = m_categories_map.GetFormat(valobj, use_dynamic);
+
+ FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
+
+ retval = m_categories_map.GetFormat(valobj, use_dynamic, matches);
+ if (!retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetFormat] Search failed. Giving language a chance.");
+ for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
+ {
+ if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
+ {
+ if (lang_category->Get(valobj, use_dynamic, matches, retval))
+ break;
+ }
+ }
+ if (retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetFormat] Language search success. Returning.");
+ return retval;
+ }
+ }
if (!retval)
{
if (log)
@@ -713,7 +774,29 @@
if (log)
log->Printf("[FormatManager::GetSummaryFormat] Cache search failed. Going normal route");
}
- retval = m_categories_map.GetSummaryFormat(valobj, use_dynamic);
+
+ FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
+
+ retval = m_categories_map.GetSummaryFormat(valobj, use_dynamic, matches);
+ if (!retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving language a chance.");
+ for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
+ {
+ if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
+ {
+ if (lang_category->Get(valobj, use_dynamic, matches, retval))
+ break;
+ }
+ }
+ if (retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetSummaryFormat] Language search success. Returning.");
+ return retval;
+ }
+ }
if (!retval)
{
if (log)
@@ -772,7 +855,29 @@
if (log)
log->Printf("[FormatManager::GetSyntheticChildren] Cache search failed. Going normal route");
}
- retval = m_categories_map.GetSyntheticChildren(valobj, use_dynamic);
+
+ FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
+
+ retval = m_categories_map.GetSyntheticChildren(valobj, use_dynamic, matches);
+ if (!retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving language a chance.");
+ for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
+ {
+ if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
+ {
+ if (lang_category->Get(valobj, use_dynamic, matches, retval))
+ break;
+ }
+ }
+ if (retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetSyntheticChildren] Language search success. Returning.");
+ return retval;
+ }
+ }
if (!retval)
{
if (log)
@@ -818,7 +923,29 @@
if (log)
log->Printf("[FormatManager::GetValidator] Cache search failed. Going normal route");
}
- retval = m_categories_map.GetValidator(valobj, use_dynamic);
+
+ FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
+
+ retval = m_categories_map.GetValidator(valobj, use_dynamic, matches);
+ if (!retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetValidator] Search failed. Giving language a chance.");
+ for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
+ {
+ if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
+ {
+ if (lang_category->Get(valobj, use_dynamic, matches, retval))
+ break;
+ }
+ }
+ if (retval)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetValidator] Language search success. Returning.");
+ return retval;
+ }
+ }
if (!retval)
{
if (log)
@@ -857,6 +984,7 @@
m_named_summaries_map(this),
m_last_revision(0),
m_categories_map(this),
+ m_language_categories_map(),
m_default_category_name(ConstString("default")),
m_system_category_name(ConstString("system")),
m_gnu_cpp_category_name(ConstString("gnu-libstdc++")),
@@ -1083,17 +1211,7 @@
lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, "std::wstring summary provider"));
TypeCategoryImpl::SharedPointer libcxx_category_sp = GetCategory(m_libcxx_category_name);
-
- libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::string"),
- std_string_summary_sp);
- libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
- std_string_summary_sp);
- libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::wstring"),
- std_wstring_summary_sp);
- libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"),
- std_wstring_summary_sp);
-
SyntheticChildren::Flags stl_synth_flags;
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
diff --git a/lldb/source/DataFormatters/LanguageCategory.cpp b/lldb/source/DataFormatters/LanguageCategory.cpp
new file mode 100644
index 0000000..5d6d432
--- /dev/null
+++ b/lldb/source/DataFormatters/LanguageCategory.cpp
@@ -0,0 +1,133 @@
+//===-- LanguageCategory.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/DataFormatters/LanguageCategory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/DataFormatters/TypeCategory.h"
+#include "lldb/DataFormatters/TypeFormat.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/DataFormatters/TypeValidator.h"
+#include "lldb/Target/Language.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LanguageCategory::LanguageCategory (lldb::LanguageType lang_type) :
+ m_category_sp(),
+ m_format_cache()
+{
+ if (Language* language_plugin = Language::FindPlugin(lang_type))
+ m_category_sp = language_plugin->GetFormatters();
+ if (m_category_sp)
+ m_category_sp->Enable(true, 1);
+}
+
+bool
+LanguageCategory::Get (ValueObject& valobj,
+ lldb::DynamicValueType dynamic,
+ FormattersMatchVector matches,
+ lldb::TypeFormatImplSP& format_sp)
+{
+ if (!m_category_sp)
+ return false;
+
+ ConstString type_name = FormatManager::GetTypeForCache(valobj, dynamic);
+ if (type_name)
+ {
+ if (m_format_cache.GetFormat(type_name, format_sp))
+ return true;
+ }
+ bool result = m_category_sp->Get(valobj, matches, format_sp);
+ if (type_name && (!format_sp || !format_sp->NonCacheable()))
+ {
+ m_format_cache.SetFormat(type_name, format_sp);
+ }
+ return result;
+}
+
+bool
+LanguageCategory::Get (ValueObject& valobj,
+ lldb::DynamicValueType dynamic,
+ FormattersMatchVector matches,
+ lldb::TypeSummaryImplSP& format_sp)
+{
+ if (!m_category_sp)
+ return false;
+
+ ConstString type_name = FormatManager::GetTypeForCache(valobj, dynamic);
+ if (type_name)
+ {
+ if (m_format_cache.GetSummary(type_name, format_sp))
+ return true;
+ }
+ bool result = m_category_sp->Get(valobj, matches, format_sp);
+ if (type_name && (!format_sp || !format_sp->NonCacheable()))
+ {
+ m_format_cache.SetSummary(type_name, format_sp);
+ }
+ return result;
+}
+
+bool
+LanguageCategory::Get (ValueObject& valobj,
+ lldb::DynamicValueType dynamic,
+ FormattersMatchVector matches,
+ lldb::SyntheticChildrenSP& format_sp)
+{
+ if (!m_category_sp)
+ return false;
+
+ ConstString type_name = FormatManager::GetTypeForCache(valobj, dynamic);
+ if (type_name)
+ {
+ if (m_format_cache.GetSynthetic(type_name, format_sp))
+ return true;
+ }
+ bool result = m_category_sp->Get(valobj, matches, format_sp);
+ if (type_name && (!format_sp || !format_sp->NonCacheable()))
+ {
+ m_format_cache.SetSynthetic(type_name, format_sp);
+ }
+ return result;
+}
+
+bool
+LanguageCategory::Get (ValueObject& valobj,
+ lldb::DynamicValueType dynamic,
+ FormattersMatchVector matches,
+ lldb::TypeValidatorImplSP& format_sp)
+{
+ if (!m_category_sp)
+ return false;
+
+ ConstString type_name = FormatManager::GetTypeForCache(valobj, dynamic);
+ if (type_name)
+ {
+ if (m_format_cache.GetValidator(type_name, format_sp))
+ return true;
+ }
+ bool result = m_category_sp->Get(valobj, matches, format_sp);
+ if (type_name && (!format_sp || !format_sp->NonCacheable()))
+ {
+ m_format_cache.SetValidator(type_name, format_sp);
+ }
+ return result;
+}
+
+lldb::TypeCategoryImplSP
+LanguageCategory::GetCategory () const
+{
+ return m_category_sp;
+}
diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp
index 96b9e6d..3494a8a 100644
--- a/lldb/source/DataFormatters/TypeCategoryMap.cpp
+++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp
@@ -219,7 +219,8 @@
lldb::TypeFormatImplSP
TypeCategoryMap::GetFormat (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+ lldb::DynamicValueType use_dynamic,
+ FormattersMatchVector matches)
{
Mutex::Locker locker(m_map_mutex);
@@ -228,8 +229,6 @@
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
- FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic);
-
for (begin = m_active_categories.begin(); begin != end; begin++)
{
lldb::TypeCategoryImplSP category_sp = *begin;
@@ -247,7 +246,8 @@
lldb::TypeSummaryImplSP
TypeCategoryMap::GetSummaryFormat (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+ lldb::DynamicValueType use_dynamic,
+ FormattersMatchVector matches)
{
Mutex::Locker locker(m_map_mutex);
@@ -256,8 +256,6 @@
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
- FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic);
-
for (begin = m_active_categories.begin(); begin != end; begin++)
{
lldb::TypeCategoryImplSP category_sp = *begin;
@@ -276,7 +274,8 @@
#ifndef LLDB_DISABLE_PYTHON
lldb::SyntheticChildrenSP
TypeCategoryMap::GetSyntheticChildren (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+ lldb::DynamicValueType use_dynamic,
+ FormattersMatchVector matches)
{
Mutex::Locker locker(m_map_mutex);
@@ -286,8 +285,6 @@
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
- FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic);
-
for (begin = m_active_categories.begin(); begin != end; begin++)
{
lldb::TypeCategoryImplSP category_sp = *begin;
@@ -306,7 +303,8 @@
lldb::TypeValidatorImplSP
TypeCategoryMap::GetValidator (ValueObject& valobj,
- lldb::DynamicValueType use_dynamic)
+ lldb::DynamicValueType use_dynamic,
+ FormattersMatchVector matches)
{
Mutex::Locker locker(m_map_mutex);
@@ -315,8 +313,6 @@
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
- FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic);
-
for (begin = m_active_categories.begin(); begin != end; begin++)
{
lldb::TypeCategoryImplSP category_sp = *begin;