llvm/lldb/examples/synthetic/recognizer_function/example.py

# Formatters for classes that derive from Message.
#
# Usage:
#   command script import ./example.py
#   type summary add --expand --recognizer-function --python-function example.message_summary example.is_message_type
#   type synth add --recognizer-function --python-class example.MessageChildProvider example.is_message_type

import sys


def is_message_type(t, internal_dict):
    for base in t.get_bases_array():
        if base.GetName() == "Message":
            return True
    return False


def message_summary(value, internal_dict):
    # Could have used a summary string as well. All the work is done by the child
    # provider.
    return "Message"


class MessageChildProvider:
    def __init__(self, value, internal_dict):
        self.value = value
        self.synthetic_children = self._analyze_children(value)

    def has_children(self):
        return self.num_children() > 0

    def num_children(self):
        return len(self.synthetic_children)

    def get_child_index(self, name):
        for index, child in enumerate(self.synthetic_children):
            if child.GetName() == name:
                return index
        return None

    def get_child_at_index(self, index):
        return self.synthetic_children[index]

    def _rename_sbvalue(self, value):
        # We want to display the field with its original name without a trailing
        # underscore. So we create a new SBValue with the same type and address but
        # a different name.
        name = value.GetName()
        assert name.endswith("_")
        new_name = name[:-1]
        return value.CreateValueFromAddress(
            new_name, value.GetLoadAddress(), value.GetType()
        )

    def _analyze_children(self, value):
        result = []
        for i in range(value.GetNumChildren()):
            child = value.GetChildAtIndex(i)
            child_name = child.GetName()
            if child_name.startswith("_"):
                continue  # Internal field, skip
            # Normal field. Check presence bit.
            presence_bit = value.GetChildMemberWithName("_has_" + child_name)
            if presence_bit.GetValueAsUnsigned() != 0:
                result.append(self._rename_sbvalue(child))
        return result