Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / examples / summaries / cocoa / CFArray.py
blobc9115738788cfebcd213c2fa439a77d02c3f9089
1 """
2 LLDB AppKit formatters
4 Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 See https://llvm.org/LICENSE.txt for license information.
6 SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 """
8 # example summary provider for NSArray
9 # the real summary is now C++ code built into LLDB
10 import lldb
11 import ctypes
12 import lldb.runtime.objc.objc_runtime
13 import lldb.formatters.metrics
14 import lldb.formatters.Logger
16 statistics = lldb.formatters.metrics.Metrics()
17 statistics.add_metric("invalid_isa")
18 statistics.add_metric("invalid_pointer")
19 statistics.add_metric("unknown_class")
20 statistics.add_metric("code_notrun")
22 # much less functional than the other two cases below
23 # just runs code to get to the count and then returns
24 # no children
27 class NSArrayKVC_SynthProvider:
28 def adjust_for_architecture(self):
29 pass
31 def __init__(self, valobj, dict, params):
32 logger = lldb.formatters.Logger.Logger()
33 self.valobj = valobj
34 self.update()
36 def update(self):
37 logger = lldb.formatters.Logger.Logger()
38 self.adjust_for_architecture()
40 def num_children(self):
41 logger = lldb.formatters.Logger.Logger()
42 stream = lldb.SBStream()
43 self.valobj.GetExpressionPath(stream)
44 num_children_vo = self.valobj.CreateValueFromExpression(
45 "count", "(int)[" + stream.GetData() + " count]"
47 if num_children_vo.IsValid():
48 return num_children_vo.GetValueAsUnsigned(0)
49 return "<variable is not NSArray>"
52 # much less functional than the other two cases below
53 # just runs code to get to the count and then returns
54 # no children
57 class NSArrayCF_SynthProvider:
58 def adjust_for_architecture(self):
59 pass
61 def __init__(self, valobj, dict, params):
62 logger = lldb.formatters.Logger.Logger()
63 self.valobj = valobj
64 self.sys_params = params
65 if not (self.sys_params.types_cache.ulong):
66 self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(
67 lldb.eBasicTypeUnsignedLong
69 self.update()
71 def update(self):
72 logger = lldb.formatters.Logger.Logger()
73 self.adjust_for_architecture()
75 def num_children(self):
76 logger = lldb.formatters.Logger.Logger()
77 num_children_vo = self.valobj.CreateChildAtOffset(
78 "count", self.sys_params.cfruntime_size, self.sys_params.types_cache.ulong
80 return num_children_vo.GetValueAsUnsigned(0)
83 class NSArrayI_SynthProvider:
84 def adjust_for_architecture(self):
85 pass
87 def __init__(self, valobj, dict, params):
88 logger = lldb.formatters.Logger.Logger()
89 self.valobj = valobj
90 self.sys_params = params
91 if not (self.sys_params.types_cache.long):
92 self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(
93 lldb.eBasicTypeLong
95 self.update()
97 def update(self):
98 logger = lldb.formatters.Logger.Logger()
99 self.adjust_for_architecture()
101 # skip the isa pointer and get at the size
102 def num_children(self):
103 logger = lldb.formatters.Logger.Logger()
104 count = self.valobj.CreateChildAtOffset(
105 "count", self.sys_params.pointer_size, self.sys_params.types_cache.long
107 return count.GetValueAsUnsigned(0)
110 class NSArrayM_SynthProvider:
111 def adjust_for_architecture(self):
112 pass
114 def __init__(self, valobj, dict, params):
115 logger = lldb.formatters.Logger.Logger()
116 self.valobj = valobj
117 self.sys_params = params
118 if not (self.sys_params.types_cache.long):
119 self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(
120 lldb.eBasicTypeLong
122 self.update()
124 def update(self):
125 logger = lldb.formatters.Logger.Logger()
126 self.adjust_for_architecture()
128 # skip the isa pointer and get at the size
129 def num_children(self):
130 logger = lldb.formatters.Logger.Logger()
131 count = self.valobj.CreateChildAtOffset(
132 "count", self.sys_params.pointer_size, self.sys_params.types_cache.long
134 return count.GetValueAsUnsigned(0)
137 # this is the actual synth provider, but is just a wrapper that checks
138 # whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an
139 # appropriate backend layer to do the computations
142 class NSArray_SynthProvider:
143 def adjust_for_architecture(self):
144 pass
146 def __init__(self, valobj, dict):
147 logger = lldb.formatters.Logger.Logger()
148 self.valobj = valobj
149 self.adjust_for_architecture()
150 self.error = False
151 self.wrapper = self.make_wrapper()
152 self.invalid = self.wrapper is None
154 def num_children(self):
155 logger = lldb.formatters.Logger.Logger()
156 if self.wrapper is None:
157 return 0
158 return self.wrapper.num_children()
160 def update(self):
161 logger = lldb.formatters.Logger.Logger()
162 if self.wrapper is None:
163 return
164 self.wrapper.update()
166 # this code acts as our defense against NULL and uninitialized
167 # NSArray pointers, which makes it much longer than it would be otherwise
168 def make_wrapper(self):
169 logger = lldb.formatters.Logger.Logger()
170 if self.valobj.GetValueAsUnsigned() == 0:
171 self.error = True
172 return lldb.runtime.objc.objc_runtime.InvalidPointer_Description(True)
173 else:
174 global statistics
176 class_data,
177 wrapper,
178 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
179 self.valobj, statistics
181 if wrapper:
182 self.error = True
183 return wrapper
185 name_string = class_data.class_name()
187 logger >> "Class name is " + str(name_string)
189 if name_string == "__NSArrayI":
190 wrapper = NSArrayI_SynthProvider(self.valobj, dict, class_data.sys_params)
191 statistics.metric_hit("code_notrun", self.valobj.GetName())
192 elif name_string == "__NSArrayM":
193 wrapper = NSArrayM_SynthProvider(self.valobj, dict, class_data.sys_params)
194 statistics.metric_hit("code_notrun", self.valobj.GetName())
195 elif name_string == "__NSCFArray":
196 wrapper = NSArrayCF_SynthProvider(self.valobj, dict, class_data.sys_params)
197 statistics.metric_hit("code_notrun", self.valobj.GetName())
198 else:
199 wrapper = NSArrayKVC_SynthProvider(self.valobj, dict, class_data.sys_params)
200 statistics.metric_hit(
201 "unknown_class", str(self.valobj.GetName()) + " seen as " + name_string
203 return wrapper
206 def CFArray_SummaryProvider(valobj, dict):
207 logger = lldb.formatters.Logger.Logger()
208 provider = NSArray_SynthProvider(valobj, dict)
209 if not provider.invalid:
210 if provider.error:
211 return provider.wrapper.message()
212 try:
213 summary = int(provider.num_children())
214 except:
215 summary = None
216 logger >> "provider gave me " + str(summary)
217 if summary is None:
218 summary = "<variable is not NSArray>"
219 elif isinstance(summary, str):
220 pass
221 else:
222 # we format it like it were a CFString to make it look the same as
223 # the summary from Xcode
224 summary = (
225 '@"' + str(summary) + (" objects" if summary != 1 else " object") + '"'
227 return summary
228 return "Summary Unavailable"
231 def __lldb_init_module(debugger, dict):
232 debugger.HandleCommand(
233 "type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef"