1"""
2LLDB Formatters for LLVM data types.
3
4Load into LLDB with 'command script import /path/to/lldbDataFormatters.py'
5"""
6
7def __lldb_init_module(debugger, internal_dict):
8    debugger.HandleCommand('type category define -e llvm -l c++')
9    debugger.HandleCommand('type synthetic add -w llvm '
10                           '-l lldbDataFormatters.SmallVectorSynthProvider '
11                           '-x "^llvm::SmallVectorImpl<.+>$"')
12    debugger.HandleCommand('type synthetic add -w llvm '
13                           '-l lldbDataFormatters.SmallVectorSynthProvider '
14                           '-x "^llvm::SmallVector<.+,.+>$"')
15    debugger.HandleCommand('type synthetic add -w llvm '
16                           '-l lldbDataFormatters.ArrayRefSynthProvider '
17                           '-x "^llvm::ArrayRef<.+>$"')
18    debugger.HandleCommand('type summary add -w llvm '
19                           '-F lldbDataFormatters.OptionalSummaryProvider '
20                           '-x "^llvm::Optional<.+>$"')
21    debugger.HandleCommand('type summary add -w llvm '
22                           '-F lldbDataFormatters.SmallStringSummaryProvider '
23                           '-x "^llvm::SmallString<.+>$"')
24
25# Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl
26class SmallVectorSynthProvider:
27    def __init__(self, valobj, dict):
28        self.valobj = valobj;
29        self.update() # initialize this provider
30
31    def num_children(self):
32        return self.size.GetValueAsUnsigned(0)
33
34    def get_child_index(self, name):
35        try:
36            return int(name.lstrip('[').rstrip(']'))
37        except:
38            return -1;
39
40    def get_child_at_index(self, index):
41        # Do bounds checking.
42        if index < 0:
43            return None
44        if index >= self.num_children():
45            return None;
46
47        offset = index * self.type_size
48        return self.begin.CreateChildAtOffset('['+str(index)+']',
49                                              offset, self.data_type)
50
51    def update(self):
52        self.begin = self.valobj.GetChildMemberWithName('BeginX')
53        self.size = self.valobj.GetChildMemberWithName('Size')
54        the_type = self.valobj.GetType()
55        # If this is a reference type we have to dereference it to get to the
56        # template parameter.
57        if the_type.IsReferenceType():
58            the_type = the_type.GetDereferencedType()
59
60        self.data_type = the_type.GetTemplateArgumentType(0)
61        self.type_size = self.data_type.GetByteSize()
62        assert self.type_size != 0
63
64class ArrayRefSynthProvider:
65    """ Provider for llvm::ArrayRef """
66    def __init__(self, valobj, dict):
67        self.valobj = valobj;
68        self.update() # initialize this provider
69
70    def num_children(self):
71        return self.length
72
73    def get_child_index(self, name):
74        try:
75            return int(name.lstrip('[').rstrip(']'))
76        except:
77            return -1;
78
79    def get_child_at_index(self, index):
80        if index < 0 or index >= self.num_children():
81            return None;
82        offset = index * self.type_size
83        return self.data.CreateChildAtOffset('[' + str(index) + ']',
84                                             offset, self.data_type)
85
86    def update(self):
87        self.data = self.valobj.GetChildMemberWithName('Data')
88        length_obj = self.valobj.GetChildMemberWithName('Length')
89        self.length = length_obj.GetValueAsUnsigned(0)
90        self.data_type = self.data.GetType().GetPointeeType()
91        self.type_size = self.data_type.GetByteSize()
92        assert self.type_size != 0
93
94def OptionalSummaryProvider(valobj, internal_dict):
95    storage = valobj.GetChildMemberWithName('Storage')
96    if not storage:
97        storage = valobj
98
99    failure = 2
100    hasVal = storage.GetChildMemberWithName('hasVal').GetValueAsUnsigned(failure)
101    if hasVal == failure:
102        return '<could not read llvm::Optional>'
103
104    if hasVal == 0:
105        return 'None'
106
107    underlying_type = storage.GetType().GetTemplateArgumentType(0)
108    storage = storage.GetChildMemberWithName('storage')
109    return str(storage.Cast(underlying_type))
110
111def SmallStringSummaryProvider(valobj, internal_dict):
112    num_elements = valobj.GetNumChildren()
113    res = "\""
114    for i in range(0, num_elements):
115      res += valobj.GetChildAtIndex(i).GetValue().strip("'")
116    res += "\""
117    return res
118