SWIGTYPE_p_lldb__SBExecutionContext);
}
+PythonObject ToSWIGWrapper(lldb::TypeImplSP type_impl_sp) {
+ return ToSWIGHelper(new lldb::SBType(type_impl_sp), SWIGTYPE_p_lldb__SBType);
+}
+
PythonObject ToSWIGWrapper(const TypeSummaryOptions &summary_options) {
return ToSWIGHelper(new lldb::SBTypeSummaryOptions(summary_options),
SWIGTYPE_p_lldb__SBTypeSummaryOptions);
return stop_at_watchpoint;
}
+// This function is called by
+// ScriptInterpreterPython::FormatterMatchingCallbackFunction and it's used when
+// a data formatter provides the name of a callback to inspect a candidate type
+// before considering a match.
+bool lldb_private::LLDBSwigPythonFormatterCallbackFunction(
+ const char *python_function_name, const char *session_dictionary_name,
+ lldb::TypeImplSP type_impl_sp) {
+
+ PyErr_Cleaner py_err_cleaner(true);
+
+ auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
+ session_dictionary_name);
+ auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
+ python_function_name, dict);
+
+ if (!pfunc.IsAllocated())
+ return false;
+
+ PythonObject result =
+ pfunc(ToSWIGWrapper(type_impl_sp), dict);
+
+ // Only if everything goes okay and the function returns True we'll consider
+ // it a match.
+ return result.get() == Py_True;
+}
+
bool lldb_private::LLDBSwigPythonCallTypeScript(
const char *python_function_name, const void *session_dictionary,
const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper,
SBType();
SBType(const lldb::SBType &rhs);
+ SBType(const lldb::TypeImplSP &);
~SBType();
SBType(const lldb_private::CompilerType &);
SBType(const lldb::TypeSP &);
- SBType(const lldb::TypeImplSP &);
};
class SBTypeList {
GetSyntheticChildren(ValueObject &valobj, lldb::DynamicValueType use_dynamic);
static bool
- AnyMatches(ConstString type_name,
+ AnyMatches(const FormattersMatchCandidate &candidate_type,
TypeCategoryImpl::FormatCategoryItems items =
TypeCategoryImpl::ALL_ITEM_TYPES,
bool only_enabled = true, const char **matching_category = nullptr,
#include "lldb/DataFormatters/TypeFormat.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/Type.h"
#include "lldb/lldb-enumerations.h"
}
};
- FormattersMatchCandidate(ConstString name, Flags flags)
- : m_type_name(name), m_flags(flags) {}
+ FormattersMatchCandidate(ConstString name,
+ ScriptInterpreter *script_interpreter, TypeImpl type,
+ Flags flags)
+ : m_type_name(name), m_script_interpreter(script_interpreter),
+ m_type(type), m_flags(flags) {}
~FormattersMatchCandidate() = default;
ConstString GetTypeName() const { return m_type_name; }
+ TypeImpl GetType() const { return m_type; }
+
+ ScriptInterpreter *GetScriptInterpreter() const {
+ return m_script_interpreter;
+ }
+
bool DidStripPointer() const { return m_flags.stripped_pointer; }
bool DidStripReference() const { return m_flags.stripped_reference; }
private:
ConstString m_type_name;
+ // If a formatter provides a matching callback function, we need the script
+ // interpreter and the type object (as an argument to the callback).
+ ScriptInterpreter *m_script_interpreter;
+ TypeImpl m_type;
Flags m_flags;
};
GetSyntheticChildren(ValueObject &valobj, lldb::DynamicValueType use_dynamic);
bool
- AnyMatches(ConstString type_name,
+ AnyMatches(const FormattersMatchCandidate &candidate_type,
TypeCategoryImpl::FormatCategoryItems items =
TypeCategoryImpl::ALL_ITEM_TYPES,
bool only_enabled = true, const char **matching_category = nullptr,
TypeCategoryImpl::FormatCategoryItems *matching_type = nullptr) {
- return m_categories_map.AnyMatches(type_name, items, only_enabled,
+ return m_categories_map.AnyMatches(candidate_type, items, only_enabled,
matching_category, matching_type);
}
/// Class for matching type names.
class TypeMatcher {
+ /// Type name for exact match, or name of the python callback if m_match_type
+ /// is `eFormatterMatchCallback`.
+ ConstString m_name;
RegularExpression m_type_name_regex;
- ConstString m_type_name;
/// Indicates what kind of matching strategy should be used:
- /// - eFormatterMatchExact: match the exact type name in m_type_name.
+ /// - eFormatterMatchExact: match the exact type name in m_name.
/// - eFormatterMatchRegex: match using the RegularExpression object
/// `m_type_name_regex` instead.
+ /// - eFormatterMatchCallback: run the function in m_name to decide if a type
+ /// matches or not.
lldb::FormatterMatchType m_match_type;
// if the user tries to add formatters for, say, "struct Foo" those will not
TypeMatcher() = delete;
/// Creates a matcher that accepts any type with exactly the given type name.
TypeMatcher(ConstString type_name)
- : m_type_name(type_name), m_match_type(lldb::eFormatterMatchExact) {}
+ : m_name(type_name), m_match_type(lldb::eFormatterMatchExact) {}
/// Creates a matcher that accepts any type matching the given regex.
TypeMatcher(RegularExpression regex)
: m_type_name_regex(std::move(regex)),
/// Creates a matcher using the matching type and string from the given type
/// name specifier.
TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier)
- : m_type_name(type_specifier->GetName()),
+ : m_name(type_specifier->GetName()),
m_match_type(type_specifier->GetMatchType()) {
if (m_match_type == lldb::eFormatterMatchRegex)
m_type_name_regex = RegularExpression(type_specifier->GetName());
}
- /// True iff this matches the given type name.
- bool Matches(ConstString type_name) const {
- if (m_match_type == lldb::eFormatterMatchRegex)
+ /// True iff this matches the given type.
+ bool Matches(FormattersMatchCandidate candidate_type) const {
+ ConstString type_name = candidate_type.GetTypeName();
+ switch (m_match_type) {
+ case lldb::eFormatterMatchExact:
+ return m_name == type_name ||
+ StripTypeName(m_name) == StripTypeName(type_name);
+ case lldb::eFormatterMatchRegex:
return m_type_name_regex.Execute(type_name.GetStringRef());
- return m_type_name == type_name ||
- StripTypeName(m_type_name) == StripTypeName(type_name);
+ case lldb::eFormatterMatchCallback:
+ // CommandObjectType{Synth,Filter}Add tries to prevent the user from
+ // creating both a synthetic child provider and a filter for the same type
+ // in the same category, but we don't have a type object at that point, so
+ // it creates a dummy candidate without type or script interpreter.
+ // Skip callback matching in these cases.
+ if (candidate_type.GetScriptInterpreter())
+ return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
+ m_name.AsCString(),
+ std::make_shared<TypeImpl>(candidate_type.GetType()));
+ }
+ return false;
}
lldb::FormatterMatchType GetMatchType() const { return m_match_type; }
/// Returns the underlying match string for this TypeMatcher.
ConstString GetMatchString() const {
+ if (m_match_type == lldb::eFormatterMatchExact)
+ return StripTypeName(m_name);
if (m_match_type == lldb::eFormatterMatchRegex)
- return ConstString(m_type_name_regex.GetText());
- return StripTypeName(m_type_name);
+ return ConstString(m_type_name_regex.GetText());
+ return m_name;
}
/// Returns true if this TypeMatcher and the given one were most created by
return false;
}
- bool Get(ConstString type, ValueSP &entry) {
+ // Finds the first formatter in the container that matches `candidate`.
+ bool Get(FormattersMatchCandidate candidate, ValueSP &entry) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
for (auto &formatter : llvm::reverse(m_map)) {
- if (formatter.first.Matches(type)) {
+ if (formatter.first.Matches(candidate)) {
entry = formatter.second;
return true;
}
return false;
}
+ // Finds the first match between candidate types in `candidates` and
+ // formatters in this container.
bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
for (const FormattersMatchCandidate &candidate : candidates) {
- if (Get(candidate.GetTypeName(), entry)) {
+ if (Get(candidate, entry)) {
if (candidate.IsMatch(entry) == false) {
entry.reset();
continue;
return false;
}
- bool AnyMatches(ConstString type_name) {
+ bool AnyMatches(const FormattersMatchCandidate &candidate) {
std::shared_ptr<FormatterImpl> entry;
for (auto sc : m_subcontainers) {
- if (sc->Get(type_name, entry))
+ if (sc->Get(FormattersMatchVector{candidate}, entry))
return true;
}
return false;
std::string GetDescription();
- bool AnyMatches(ConstString type_name,
+ bool AnyMatches(const FormattersMatchCandidate &candidate_type,
FormatCategoryItems items = ALL_ITEM_TYPES,
bool only_enabled = true,
const char **matching_category = nullptr,
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"
+#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/FormattersContainer.h"
#include "lldb/DataFormatters/TypeCategory.h"
lldb::TypeCategoryImplSP GetAtIndex(uint32_t);
bool
- AnyMatches(ConstString type_name,
+ AnyMatches(const FormattersMatchCandidate &candidate_type,
TypeCategoryImpl::FormatCategoryItems items =
TypeCategoryImpl::ALL_ITEM_TYPES,
bool only_enabled = true, const char **matching_category = nullptr,
return false;
}
+ // Calls the specified formatter matching Python function and returns its
+ // result (true if it's a match, false if we should keep looking for a
+ // matching formatter).
+ virtual bool FormatterCallbackFunction(const char *function_name,
+ lldb::TypeImplSP type_impl_sp) {
+ return true;
+ }
+
virtual void Clear() {
// Clean up any ref counts to SBObjects that might be in global variables
}
virtual HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics();
- virtual std::vector<ConstString>
+ virtual std::vector<FormattersMatchCandidate>
GetPossibleFormattersMatches(ValueObject &valobj,
lldb::DynamicValueType use_dynamic);
enum FormatterMatchType {
eFormatterMatchExact,
eFormatterMatchRegex,
+ eFormatterMatchCallback,
- eLastFormatterMatchType = eFormatterMatchRegex,
+ eLastFormatterMatchType = eFormatterMatchCallback,
};
/// Options that can be set for a formatter to alter its behavior. Not
lldb::SBStream &description, lldb::DescriptionLevel description_level) {
LLDB_INSTRUMENT_VA(this, description, description_level);
+ lldb::FormatterMatchType match_type = GetMatchType();
+ const char *match_type_str =
+ (match_type == eFormatterMatchExact ? "plain"
+ : match_type == eFormatterMatchRegex ? "regex"
+ : "callback");
if (!IsValid())
return false;
- description.Printf("SBTypeNameSpecifier(%s,%s)", GetName(),
- IsRegex() ? "regex" : "plain");
+ description.Printf("SBTypeNameSpecifier(%s,%s)", GetName(), match_type_str);
return true;
}
#include "lldb/Core/Debugger.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
// an actual type name. Matching a regex string against registered regexes
// doesn't work.
if (type == eRegularSynth) {
- if (category->AnyMatches(type_name, eFormatCategoryItemFilter, false)) {
+ // It's not generally possible to get a type object here. For example, this
+ // command can be run before loading any binaries. Do just a best-effort
+ // name-based lookup here to try to prevent conflicts.
+ FormattersMatchCandidate candidate_type(type_name, nullptr, TypeImpl(),
+ FormattersMatchCandidate::Flags());
+ if (category->AnyMatches(candidate_type, eFormatCategoryItemFilter,
+ false)) {
if (error)
error->SetErrorStringWithFormat("cannot add synthetic for type %s when "
"filter is defined in same category!",
// if `type_name` is an actual type name. Matching a regex string against
// registered regexes doesn't work.
if (type == eRegularFilter) {
- if (category->AnyMatches(type_name, eFormatCategoryItemSynth, false)) {
+ // It's not generally possible to get a type object here. For example,
+ // this command can be run before loading any binaries. Do just a
+ // best-effort name-based lookup here to try to prevent conflicts.
+ FormattersMatchCandidate candidate_type(
+ type_name, nullptr, TypeImpl(), FormattersMatchCandidate::Flags());
+ lldb::SyntheticChildrenSP entry;
+ if (category->AnyMatches(candidate_type, eFormatCategoryItemSynth,
+ false)) {
if (error)
error->SetErrorStringWithFormat("cannot add filter for type %s when "
"synthetic is defined in same "
}
bool DataVisualization::AnyMatches(
- ConstString type_name, TypeCategoryImpl::FormatCategoryItems items,
- bool only_enabled, const char **matching_category,
+ const FormattersMatchCandidate &candidate_type,
+ TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
+ const char **matching_category,
TypeCategoryImpl::FormatCategoryItems *matching_type) {
- return GetFormatManager().AnyMatches(type_name, items, only_enabled,
+ return GetFormatManager().AnyMatches(candidate_type, items, only_enabled,
matching_category, matching_type);
}
#include "lldb/Core/Debugger.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/LanguageCategory.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Utility/LLDBLog.h"
FormattersMatchCandidate::Flags current_flags, bool root_level) {
compiler_type = compiler_type.GetTypeForFormatters();
ConstString type_name(compiler_type.GetTypeName());
+ ScriptInterpreter *script_interpreter =
+ valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter();
if (valobj.GetBitfieldBitSize() > 0) {
StreamString sstring;
sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize());
ConstString bitfieldname(sstring.GetString());
- entries.push_back({bitfieldname, current_flags});
+ entries.push_back({bitfieldname, script_interpreter,
+ TypeImpl(compiler_type), current_flags});
}
if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) {
- entries.push_back({type_name, current_flags});
+ entries.push_back({type_name, script_interpreter, TypeImpl(compiler_type),
+ current_flags});
ConstString display_type_name(compiler_type.GetTypeName());
if (display_type_name != type_name)
- entries.push_back({display_type_name, current_flags});
+ entries.push_back({display_type_name, script_interpreter,
+ TypeImpl(compiler_type), current_flags});
}
for (bool is_rvalue_ref = true, j = true;
for (lldb::LanguageType language_type :
GetCandidateLanguages(valobj.GetObjectRuntimeLanguage())) {
if (Language *language = Language::FindPlugin(language_type)) {
- for (ConstString candidate :
+ for (const FormattersMatchCandidate& candidate :
language->GetPossibleFormattersMatches(valobj, use_dynamic)) {
- entries.push_back({candidate, current_flags});
+ entries.push_back(candidate);
}
}
}
return count;
}
-bool TypeCategoryImpl::AnyMatches(ConstString type_name,
- FormatCategoryItems items, bool only_enabled,
- const char **matching_category,
- FormatCategoryItems *matching_type) {
+bool TypeCategoryImpl::AnyMatches(
+ const FormattersMatchCandidate &candidate_type, FormatCategoryItems items,
+ bool only_enabled, const char **matching_category,
+ FormatCategoryItems *matching_type) {
if (!IsEnabled() && only_enabled)
return false;
- lldb::TypeFormatImplSP format_sp;
- lldb::TypeSummaryImplSP summary_sp;
- TypeFilterImpl::SharedPointer filter_sp;
- ScriptedSyntheticChildren::SharedPointer synth_sp;
-
if (items & eFormatCategoryItemFormat) {
- if (m_format_cont.AnyMatches(type_name)) {
+ if (m_format_cont.AnyMatches(candidate_type)) {
if (matching_category)
*matching_category = m_name.GetCString();
if (matching_type)
}
if (items & eFormatCategoryItemSummary) {
- if (m_summary_cont.AnyMatches(type_name)) {
+ if (m_summary_cont.AnyMatches(candidate_type)) {
if (matching_category)
*matching_category = m_name.GetCString();
if (matching_type)
}
if (items & eFormatCategoryItemFilter) {
- if (m_filter_cont.AnyMatches(type_name)) {
+ if (m_filter_cont.AnyMatches(candidate_type)) {
if (matching_category)
*matching_category = m_name.GetCString();
if (matching_type)
}
if (items & eFormatCategoryItemSynth) {
- if (m_synth_cont.AnyMatches(type_name)) {
+ if (m_synth_cont.AnyMatches(candidate_type)) {
if (matching_category)
*matching_category = m_name.GetCString();
if (matching_type)
}
bool TypeCategoryMap::AnyMatches(
- ConstString type_name, TypeCategoryImpl::FormatCategoryItems items,
- bool only_enabled, const char **matching_category,
+ const FormattersMatchCandidate &candidate_type,
+ TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
+ const char **matching_category,
TypeCategoryImpl::FormatCategoryItems *matching_type) {
std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
MapIterator pos, end = m_map.end();
for (pos = m_map.begin(); pos != end; pos++) {
- if (pos->second->AnyMatches(type_name, items, only_enabled,
+ if (pos->second->AnyMatches(candidate_type, items, only_enabled,
matching_category, matching_type))
return true;
}
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/DataVisualization.h"
return g_category;
}
-std::vector<ConstString>
+std::vector<FormattersMatchCandidate>
ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
- std::vector<ConstString> result;
+ std::vector<FormattersMatchCandidate> result;
if (use_dynamic == lldb::eNoDynamicValues)
return result;
if (!objc_class_sp)
break;
if (ConstString name = objc_class_sp->GetClassName())
- result.push_back(name);
+ result.push_back(
+ {name, valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter(),
+ TypeImpl(objc_class_sp->GetType()),
+ FormattersMatchCandidate::Flags{}});
} while (false);
}
lldb::TypeCategoryImplSP GetFormatters() override;
- std::vector<ConstString>
+ std::vector<FormattersMatchCandidate>
GetPossibleFormattersMatches(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) override;
const char *python_function_name, const char *session_dictionary_name,
const lldb::StackFrameSP &sb_frame, const lldb::WatchpointSP &sb_wp);
+bool LLDBSwigPythonFormatterCallbackFunction(
+ const char *python_function_name, const char *session_dictionary_name,
+ lldb::TypeImplSP type_impl_sp);
+
bool LLDBSwigPythonCallTypeScript(const char *python_function_name,
const void *session_dictionary,
const lldb::ValueObjectSP &valobj_sp,
return ret_val;
}
+bool ScriptInterpreterPythonImpl::FormatterCallbackFunction(
+ const char *python_function_name, TypeImplSP type_impl_sp) {
+ Locker py_lock(this,
+ Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ return LLDBSwigPythonFormatterCallbackFunction(
+ python_function_name, m_dictionary_name.c_str(), type_impl_sp);
+}
+
bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction(
void *baton, StoppointCallbackContext *context, user_id_t break_id,
user_id_t break_loc_id) {
const TypeSummaryOptions &options,
std::string &retval) override;
+ bool FormatterCallbackFunction(const char *function_name,
+ lldb::TypeImplSP type_impl_sp) override;
+
bool GetDocumentationForItem(const char *item, std::string &dest) override;
bool GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
return {};
}
-std::vector<ConstString>
+std::vector<FormattersMatchCandidate>
Language::GetPossibleFormattersMatches(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
return {};
--- /dev/null
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
--- /dev/null
+"""
+Test lldb data formatter callback-based matching.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class PythonSynthDataFormatterTestCase(TestBase):
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number to break at.
+ self.line = line_number('main.cpp', '// Set break point at this line.')
+
+ def test_callback_matchers(self):
+ """Test data formatter commands."""
+ self.build()
+
+ _, process, thread, _ = lldbutil.run_to_line_breakpoint(
+ self, lldb.SBFileSpec("main.cpp"), self.line)
+
+ # Print derived without a formatter.
+ self.expect("frame variable derived",
+ substrs=['x = 2222',
+ 'y = 3333'])
+
+ # now set up a summary function that uses a python callback to match
+ # classes that derive from `Base`.
+ self.runCmd("command script import --allow-reload ./formatters_with_callback.py")
+
+ # Now `derived` should use our callback summary + synthetic children.
+ self.expect("frame variable derived",
+ substrs=['hello from callback summary',
+ 'synthetic_child = 9999'])
+
+ # But not other classes.
+ self.expect("frame variable base", matching=False,
+ substrs=['hello from callback summary'])
+ self.expect("frame variable base",
+ substrs=['x = 1111'])
+
+ self.expect("frame variable nd", matching=False,
+ substrs=['hello from callback summary'])
+ self.expect("frame variable nd",
+ substrs=['z = 4444'])
--- /dev/null
+import lldb
+
+def derives_from_base(sbtype, internal_dict):
+ for base in sbtype.get_bases_array():
+ if base.GetName() == "Base":
+ return True
+ return False
+
+
+class SynthProvider:
+ def __init__(self, valobj, dict):
+ self.valobj = valobj
+
+ def num_children(self):
+ return 1
+
+ def get_child_index(self, name):
+ return 0
+
+ def get_child_at_index(self, index):
+ if index == 0:
+ return self.valobj.CreateValueFromExpression("synthetic_child",
+ "9999")
+ return None
+
+
+def __lldb_init_module(debugger, dict):
+ cat = debugger.CreateCategory("callback_formatters")
+ cat.AddTypeSummary(
+ lldb.SBTypeNameSpecifier("formatters_with_callback.derives_from_base",
+ lldb.eFormatterMatchCallback),
+ lldb.SBTypeSummary.CreateWithScriptCode(
+ "return 'hello from callback summary'"))
+ cat.AddTypeSynthetic(
+ lldb.SBTypeNameSpecifier('formatters_with_callback.derives_from_base',
+ lldb.eFormatterMatchCallback),
+ lldb.SBTypeSynthetic.CreateWithClassName(
+ 'formatters_with_callback.SynthProvider'))
+ cat.SetEnabled(True)
--- /dev/null
+struct Base { int x; };
+struct Derived : public Base { int y; };
+
+struct NonDerived { int z; };
+
+int main()
+{
+ Base base = {1111};
+
+ Derived derived;
+ derived.x = 2222;
+ derived.y = 3333;
+
+ NonDerived nd = {4444};
+ return 0; // Set break point at this line.
+}
//===----------------------------------------------------------------------===//
#include "lldb/DataFormatters/FormattersContainer.h"
+#include "lldb/DataFormatters/FormatClasses.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
+// Creates a dummy candidate with just a type name in order to test the string
+// matching (exact name match and regex match) paths.
+FormattersMatchCandidate CandidateFromTypeName(const char *type_name) {
+ return FormattersMatchCandidate(ConstString(type_name), nullptr, TypeImpl(),
+ FormattersMatchCandidate::Flags());
+}
+
// All the prefixes that the exact name matching will strip from the type.
static const std::vector<std::string> exact_name_prefixes = {
"", // no prefix.
SCOPED_TRACE("Prefix: " + prefix);
TypeMatcher matcher(ConstString(prefix + "Name"));
- EXPECT_TRUE(matcher.Matches(ConstString("class Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("struct Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("union Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("enum Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("Name")));
-
- EXPECT_FALSE(matcher.Matches(ConstString("Name ")));
- EXPECT_FALSE(matcher.Matches(ConstString("ame")));
- EXPECT_FALSE(matcher.Matches(ConstString("Nam")));
- EXPECT_FALSE(matcher.Matches(ConstString("am")));
- EXPECT_FALSE(matcher.Matches(ConstString("a")));
- EXPECT_FALSE(matcher.Matches(ConstString(" ")));
- EXPECT_FALSE(matcher.Matches(ConstString("class N")));
- EXPECT_FALSE(matcher.Matches(ConstString("class ")));
- EXPECT_FALSE(matcher.Matches(ConstString("class")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("class Name")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("struct Name")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("union Name")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("enum Name")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("Name")));
+
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("Name ")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ame")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("Nam")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("am")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("a")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(" ")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class N")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class ")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class")));
}
}
// TypeMatcher that uses a regex to match a type name.
TEST(TypeMatcherTests, RegexName) {
TypeMatcher matcher(RegularExpression("^a[a-z]c$"));
- EXPECT_TRUE(matcher.Matches(ConstString("abc")));
- EXPECT_TRUE(matcher.Matches(ConstString("azc")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("abc")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("azc")));
// FIXME: This isn't consistent with the 'exact' type name matches above.
- EXPECT_FALSE(matcher.Matches(ConstString("class abc")));
-
- EXPECT_FALSE(matcher.Matches(ConstString("abbc")));
- EXPECT_FALSE(matcher.Matches(ConstString(" abc")));
- EXPECT_FALSE(matcher.Matches(ConstString("abc ")));
- EXPECT_FALSE(matcher.Matches(ConstString(" abc ")));
- EXPECT_FALSE(matcher.Matches(ConstString("XabcX")));
- EXPECT_FALSE(matcher.Matches(ConstString("ac")));
- EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c")));
- EXPECT_FALSE(matcher.Matches(ConstString("aAc")));
- EXPECT_FALSE(matcher.Matches(ConstString("ABC")));
- EXPECT_FALSE(matcher.Matches(ConstString("")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("class abc")));
+
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("abbc")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(" abc")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("abc ")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName(" abc ")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("XabcX")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ac")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("a[a-z]c")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("aAc")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ABC")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("")));
}
// TypeMatcher that only searches the type name.
TEST(TypeMatcherTests, RegexMatchPart) {
TypeMatcher matcher(RegularExpression("a[a-z]c"));
- EXPECT_TRUE(matcher.Matches(ConstString("class abc")));
- EXPECT_TRUE(matcher.Matches(ConstString("abc")));
- EXPECT_TRUE(matcher.Matches(ConstString(" abc ")));
- EXPECT_TRUE(matcher.Matches(ConstString("azc")));
- EXPECT_TRUE(matcher.Matches(ConstString("abc ")));
- EXPECT_TRUE(matcher.Matches(ConstString(" abc ")));
- EXPECT_TRUE(matcher.Matches(ConstString(" abc")));
- EXPECT_TRUE(matcher.Matches(ConstString("XabcX")));
-
- EXPECT_FALSE(matcher.Matches(ConstString("abbc")));
- EXPECT_FALSE(matcher.Matches(ConstString("ac")));
- EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c")));
- EXPECT_FALSE(matcher.Matches(ConstString("aAc")));
- EXPECT_FALSE(matcher.Matches(ConstString("ABC")));
- EXPECT_FALSE(matcher.Matches(ConstString("")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("class abc")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("abc")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName(" abc ")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("azc")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("abc ")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName(" abc ")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName(" abc")));
+ EXPECT_TRUE(matcher.Matches(CandidateFromTypeName("XabcX")));
+
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("abbc")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ac")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("a[a-z]c")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("aAc")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("ABC")));
+ EXPECT_FALSE(matcher.Matches(CandidateFromTypeName("")));
}
// GetMatchString for exact type name matchers.
return false;
}
+bool lldb_private::LLDBSwigPythonFormatterCallbackFunction(
+ const char *python_function_name, const char *session_dictionary_name,
+ lldb::TypeImplSP type_impl_sp) {
+ return false;
+}
+
bool lldb_private::LLDBSwigPythonCallTypeScript(
const char *python_function_name, const void *session_dictionary,
const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper,