Add support for language plugins to provide data formatters (second attempt)

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: 246568
diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp
index e41d341..5c39b2a 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,21 @@
     return validator_chosen_sp;
 }
 
+void
+FormatManager::LoopThroughCategories (CategoryCallback callback, void* param)
+{
+    m_categories_map.LoopThrough(callback, param);
+    Mutex::Locker locker(m_language_categories_mutex);
+    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 +614,8 @@
 }
 
 ConstString
-GetTypeForCache (ValueObject& valobj,
-                 lldb::DynamicValueType use_dynamic)
+FormatManager::GetTypeForCache (ValueObject& valobj,
+                                lldb::DynamicValueType use_dynamic)
 {
     if (use_dynamic == lldb::eNoDynamicValues)
     {
@@ -618,6 +636,29 @@
     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)
+{
+    Mutex::Locker locker(m_language_categories_mutex);
+    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 +696,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 +776,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 +857,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 +925,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 +986,8 @@
     m_named_summaries_map(this),
     m_last_revision(0),
     m_categories_map(this),
+    m_language_categories_map(),
+    m_language_categories_mutex(Mutex::eMutexTypeRecursive),
     m_default_category_name(ConstString("default")),
     m_system_category_name(ConstString("system")), 
     m_gnu_cpp_category_name(ConstString("gnu-libstdc++")),
@@ -1083,16 +1214,16 @@
     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::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);
+                                                         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);
+                                                         std_wstring_summary_sp);
     
     SyntheticChildren::Flags stl_synth_flags;
     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);