xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
1 //===-- ObjCLanguage.cpp ----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <mutex>
10 
11 #include "ObjCLanguage.h"
12 
13 #include "lldb/Core/PluginManager.h"
14 #include "lldb/Core/ValueObject.h"
15 #include "lldb/DataFormatters/DataVisualization.h"
16 #include "lldb/DataFormatters/FormattersHelpers.h"
17 #include "lldb/Symbol/ClangASTContext.h"
18 #include "lldb/Symbol/CompilerType.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Utility/ConstString.h"
21 #include "lldb/Utility/StreamString.h"
22 
23 #include "llvm/Support/Threading.h"
24 
25 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
26 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
27 
28 #include "CF.h"
29 #include "Cocoa.h"
30 #include "CoreMedia.h"
31 #include "NSDictionary.h"
32 #include "NSSet.h"
33 #include "NSString.h"
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 using namespace lldb_private::formatters;
38 
39 void ObjCLanguage::Initialize() {
40   PluginManager::RegisterPlugin(GetPluginNameStatic(), "Objective-C Language",
41                                 CreateInstance);
42 }
43 
44 void ObjCLanguage::Terminate() {
45   PluginManager::UnregisterPlugin(CreateInstance);
46 }
47 
48 lldb_private::ConstString ObjCLanguage::GetPluginNameStatic() {
49   static ConstString g_name("objc");
50   return g_name;
51 }
52 
53 // PluginInterface protocol
54 
55 lldb_private::ConstString ObjCLanguage::GetPluginName() {
56   return GetPluginNameStatic();
57 }
58 
59 uint32_t ObjCLanguage::GetPluginVersion() { return 1; }
60 
61 // Static Functions
62 
63 Language *ObjCLanguage::CreateInstance(lldb::LanguageType language) {
64   switch (language) {
65   case lldb::eLanguageTypeObjC:
66     return new ObjCLanguage();
67   default:
68     return nullptr;
69   }
70 }
71 
72 void ObjCLanguage::MethodName::Clear() {
73   m_full.Clear();
74   m_class.Clear();
75   m_category.Clear();
76   m_selector.Clear();
77   m_type = eTypeUnspecified;
78   m_category_is_valid = false;
79 }
80 
81 bool ObjCLanguage::MethodName::SetName(llvm::StringRef name, bool strict) {
82   Clear();
83   if (name.empty())
84     return IsValid(strict);
85 
86   // If "strict" is true. then the method must be specified with a '+' or '-'
87   // at the beginning. If "strict" is false, then the '+' or '-' can be omitted
88   bool valid_prefix = false;
89 
90   if (name.size() > 1 && (name[0] == '+' || name[0] == '-')) {
91     valid_prefix = name[1] == '[';
92     if (name[0] == '+')
93       m_type = eTypeClassMethod;
94     else
95       m_type = eTypeInstanceMethod;
96   } else if (!strict) {
97     // "strict" is false, the name just needs to start with '['
98     valid_prefix = name[0] == '[';
99   }
100 
101   if (valid_prefix) {
102     int name_len = name.size();
103     // Objective-C methods must have at least:
104     //      "-[" or "+[" prefix
105     //      One character for a class name
106     //      One character for the space between the class name
107     //      One character for the method name
108     //      "]" suffix
109     if (name_len >= (5 + (strict ? 1 : 0)) && name.back() == ']') {
110       m_full.SetString(name);
111     }
112   }
113   return IsValid(strict);
114 }
115 
116 bool ObjCLanguage::MethodName::SetName(const char *name, bool strict) {
117   return SetName(llvm::StringRef(name), strict);
118 }
119 
120 ConstString ObjCLanguage::MethodName::GetClassName() {
121   if (!m_class) {
122     if (IsValid(false)) {
123       const char *full = m_full.GetCString();
124       const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
125       const char *paren_pos = strchr(class_start, '(');
126       if (paren_pos) {
127         m_class.SetCStringWithLength(class_start, paren_pos - class_start);
128       } else {
129         // No '(' was found in the full name, we can definitively say that our
130         // category was valid (and empty).
131         m_category_is_valid = true;
132         const char *space_pos = strchr(full, ' ');
133         if (space_pos) {
134           m_class.SetCStringWithLength(class_start, space_pos - class_start);
135           if (!m_class_category) {
136             // No category in name, so we can also fill in the m_class_category
137             m_class_category = m_class;
138           }
139         }
140       }
141     }
142   }
143   return m_class;
144 }
145 
146 ConstString ObjCLanguage::MethodName::GetClassNameWithCategory() {
147   if (!m_class_category) {
148     if (IsValid(false)) {
149       const char *full = m_full.GetCString();
150       const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
151       const char *space_pos = strchr(full, ' ');
152       if (space_pos) {
153         m_class_category.SetCStringWithLength(class_start,
154                                               space_pos - class_start);
155         // If m_class hasn't been filled in and the class with category doesn't
156         // contain a '(', then we can also fill in the m_class
157         if (!m_class && strchr(m_class_category.GetCString(), '(') == nullptr) {
158           m_class = m_class_category;
159           // No '(' was found in the full name, we can definitively say that
160           // our category was valid (and empty).
161           m_category_is_valid = true;
162         }
163       }
164     }
165   }
166   return m_class_category;
167 }
168 
169 ConstString ObjCLanguage::MethodName::GetSelector() {
170   if (!m_selector) {
171     if (IsValid(false)) {
172       const char *full = m_full.GetCString();
173       const char *space_pos = strchr(full, ' ');
174       if (space_pos) {
175         ++space_pos; // skip the space
176         m_selector.SetCStringWithLength(space_pos, m_full.GetLength() -
177                                                        (space_pos - full) - 1);
178       }
179     }
180   }
181   return m_selector;
182 }
183 
184 ConstString ObjCLanguage::MethodName::GetCategory() {
185   if (!m_category_is_valid && !m_category) {
186     if (IsValid(false)) {
187       m_category_is_valid = true;
188       const char *full = m_full.GetCString();
189       const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
190       const char *open_paren_pos = strchr(class_start, '(');
191       if (open_paren_pos) {
192         ++open_paren_pos; // Skip the open paren
193         const char *close_paren_pos = strchr(open_paren_pos, ')');
194         if (close_paren_pos)
195           m_category.SetCStringWithLength(open_paren_pos,
196                                           close_paren_pos - open_paren_pos);
197       }
198     }
199   }
200   return m_category;
201 }
202 
203 ConstString ObjCLanguage::MethodName::GetFullNameWithoutCategory(
204     bool empty_if_no_category) {
205   if (IsValid(false)) {
206     if (HasCategory()) {
207       StreamString strm;
208       if (m_type == eTypeClassMethod)
209         strm.PutChar('+');
210       else if (m_type == eTypeInstanceMethod)
211         strm.PutChar('-');
212       strm.Printf("[%s %s]", GetClassName().GetCString(),
213                   GetSelector().GetCString());
214       return ConstString(strm.GetString());
215     }
216 
217     if (!empty_if_no_category) {
218       // Just return the full name since it doesn't have a category
219       return GetFullName();
220     }
221   }
222   return ConstString();
223 }
224 
225 std::vector<ConstString>
226 ObjCLanguage::GetMethodNameVariants(ConstString method_name) const {
227   std::vector<ConstString> variant_names;
228   ObjCLanguage::MethodName objc_method(method_name.GetCString(), false);
229   if (!objc_method.IsValid(false)) {
230     return variant_names;
231   }
232 
233   const bool is_class_method =
234       objc_method.GetType() == MethodName::eTypeClassMethod;
235   const bool is_instance_method =
236       objc_method.GetType() == MethodName::eTypeInstanceMethod;
237   ConstString name_sans_category =
238       objc_method.GetFullNameWithoutCategory(/*empty_if_no_category*/ true);
239 
240   if (is_class_method || is_instance_method) {
241     if (name_sans_category)
242       variant_names.emplace_back(name_sans_category);
243   } else {
244     StreamString strm;
245 
246     strm.Printf("+%s", objc_method.GetFullName().GetCString());
247     variant_names.emplace_back(strm.GetString());
248     strm.Clear();
249 
250     strm.Printf("-%s", objc_method.GetFullName().GetCString());
251     variant_names.emplace_back(strm.GetString());
252     strm.Clear();
253 
254     if (name_sans_category) {
255       strm.Printf("+%s", name_sans_category.GetCString());
256       variant_names.emplace_back(strm.GetString());
257       strm.Clear();
258 
259       strm.Printf("-%s", name_sans_category.GetCString());
260       variant_names.emplace_back(strm.GetString());
261     }
262   }
263 
264   return variant_names;
265 }
266 
267 static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) {
268   if (!objc_category_sp)
269     return;
270 
271   TypeSummaryImpl::Flags objc_flags;
272   objc_flags.SetCascades(false)
273       .SetSkipPointers(true)
274       .SetSkipReferences(true)
275       .SetDontShowChildren(true)
276       .SetDontShowValue(true)
277       .SetShowMembersOneLiner(false)
278       .SetHideItemNames(false);
279 
280   lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat(
281       objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider, ""));
282   objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL"),
283                                                      ObjC_BOOL_summary);
284   objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL &"),
285                                                      ObjC_BOOL_summary);
286   objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL *"),
287                                                      ObjC_BOOL_summary);
288 
289   // we need to skip pointers here since we are special casing a SEL* when
290   // retrieving its value
291   objc_flags.SetSkipPointers(true);
292   AddCXXSummary(objc_category_sp,
293                 lldb_private::formatters::ObjCSELSummaryProvider<false>,
294                 "SEL summary provider", ConstString("SEL"), objc_flags);
295   AddCXXSummary(
296       objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<false>,
297       "SEL summary provider", ConstString("struct objc_selector"), objc_flags);
298   AddCXXSummary(
299       objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<false>,
300       "SEL summary provider", ConstString("objc_selector"), objc_flags);
301   AddCXXSummary(
302       objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<true>,
303       "SEL summary provider", ConstString("objc_selector *"), objc_flags);
304   AddCXXSummary(objc_category_sp,
305                 lldb_private::formatters::ObjCSELSummaryProvider<true>,
306                 "SEL summary provider", ConstString("SEL *"), objc_flags);
307 
308   AddCXXSummary(objc_category_sp,
309                 lldb_private::formatters::ObjCClassSummaryProvider,
310                 "Class summary provider", ConstString("Class"), objc_flags);
311 
312   SyntheticChildren::Flags class_synth_flags;
313   class_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
314       false);
315 
316   AddCXXSynthetic(objc_category_sp,
317                   lldb_private::formatters::ObjCClassSyntheticFrontEndCreator,
318                   "Class synthetic children", ConstString("Class"),
319                   class_synth_flags);
320 
321   objc_flags.SetSkipPointers(false);
322   objc_flags.SetCascades(true);
323   objc_flags.SetSkipReferences(false);
324 
325   AddStringSummary(objc_category_sp, "${var.__FuncPtr%A}",
326                    ConstString("__block_literal_generic"), objc_flags);
327 
328   AddStringSummary(objc_category_sp, "${var.years} years, ${var.months} "
329                                      "months, ${var.days} days, ${var.hours} "
330                                      "hours, ${var.minutes} minutes "
331                                      "${var.seconds} seconds",
332                    ConstString("CFGregorianUnits"), objc_flags);
333   AddStringSummary(objc_category_sp,
334                    "location=${var.location} length=${var.length}",
335                    ConstString("CFRange"), objc_flags);
336 
337   AddStringSummary(objc_category_sp,
338                    "location=${var.location}, length=${var.length}",
339                    ConstString("NSRange"), objc_flags);
340   AddStringSummary(objc_category_sp, "(${var.origin}, ${var.size}), ...",
341                    ConstString("NSRectArray"), objc_flags);
342 
343   AddOneLineSummary(objc_category_sp, ConstString("NSPoint"), objc_flags);
344   AddOneLineSummary(objc_category_sp, ConstString("NSSize"), objc_flags);
345   AddOneLineSummary(objc_category_sp, ConstString("NSRect"), objc_flags);
346 
347   AddOneLineSummary(objc_category_sp, ConstString("CGSize"), objc_flags);
348   AddOneLineSummary(objc_category_sp, ConstString("CGPoint"), objc_flags);
349   AddOneLineSummary(objc_category_sp, ConstString("CGRect"), objc_flags);
350 
351   AddStringSummary(objc_category_sp,
352                    "red=${var.red} green=${var.green} blue=${var.blue}",
353                    ConstString("RGBColor"), objc_flags);
354   AddStringSummary(
355       objc_category_sp,
356       "(t=${var.top}, l=${var.left}, b=${var.bottom}, r=${var.right})",
357       ConstString("Rect"), objc_flags);
358   AddStringSummary(objc_category_sp, "{(v=${var.v}, h=${var.h})}",
359                    ConstString("Point"), objc_flags);
360   AddStringSummary(objc_category_sp,
361                    "${var.month}/${var.day}/${var.year}  ${var.hour} "
362                    ":${var.minute} :${var.second} dayOfWeek:${var.dayOfWeek}",
363                    ConstString("DateTimeRect *"), objc_flags);
364   AddStringSummary(objc_category_sp, "${var.ld.month}/${var.ld.day}/"
365                                      "${var.ld.year} ${var.ld.hour} "
366                                      ":${var.ld.minute} :${var.ld.second} "
367                                      "dayOfWeek:${var.ld.dayOfWeek}",
368                    ConstString("LongDateRect"), objc_flags);
369   AddStringSummary(objc_category_sp, "(x=${var.x}, y=${var.y})",
370                    ConstString("HIPoint"), objc_flags);
371   AddStringSummary(objc_category_sp, "origin=${var.origin} size=${var.size}",
372                    ConstString("HIRect"), objc_flags);
373 
374   TypeSummaryImpl::Flags appkit_flags;
375   appkit_flags.SetCascades(true)
376       .SetSkipPointers(false)
377       .SetSkipReferences(false)
378       .SetDontShowChildren(true)
379       .SetDontShowValue(false)
380       .SetShowMembersOneLiner(false)
381       .SetHideItemNames(false);
382 
383   appkit_flags.SetDontShowChildren(false);
384 
385   AddCXXSummary(
386       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
387       "NSArray summary provider", ConstString("NSArray"), appkit_flags);
388   AddCXXSummary(
389       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
390       "NSArray summary provider", ConstString("NSMutableArray"), appkit_flags);
391   AddCXXSummary(
392       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
393       "NSArray summary provider", ConstString("__NSArrayI"), appkit_flags);
394   AddCXXSummary(
395       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
396       "NSArray summary provider", ConstString("__NSArray0"), appkit_flags);
397   AddCXXSummary(objc_category_sp,
398                 lldb_private::formatters::NSArraySummaryProvider,
399                 "NSArray summary provider",
400                 ConstString("__NSSingleObjectArrayI"), appkit_flags);
401   AddCXXSummary(
402       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
403       "NSArray summary provider", ConstString("__NSArrayM"), appkit_flags);
404   AddCXXSummary(
405       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
406       "NSArray summary provider", ConstString("__NSCFArray"), appkit_flags);
407   AddCXXSummary(
408       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
409       "NSArray summary provider", ConstString("_NSCallStackArray"), appkit_flags);
410   AddCXXSummary(
411       objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
412       "NSArray summary provider", ConstString("CFArrayRef"), appkit_flags);
413   AddCXXSummary(objc_category_sp,
414                 lldb_private::formatters::NSArraySummaryProvider,
415                 "NSArray summary provider", ConstString("CFMutableArrayRef"),
416                 appkit_flags);
417 
418   AddCXXSummary(objc_category_sp,
419                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
420                 "NSDictionary summary provider", ConstString("NSDictionary"),
421                 appkit_flags);
422   AddCXXSummary(objc_category_sp,
423                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
424                 "NSDictionary summary provider",
425                 ConstString("NSMutableDictionary"), appkit_flags);
426   AddCXXSummary(objc_category_sp,
427                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
428                 "NSDictionary summary provider",
429                 ConstString("__NSCFDictionary"), appkit_flags);
430   AddCXXSummary(objc_category_sp,
431                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
432                 "NSDictionary summary provider", ConstString("__NSDictionaryI"),
433                 appkit_flags);
434   AddCXXSummary(objc_category_sp,
435                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
436                 "NSDictionary summary provider",
437                 ConstString("__NSSingleEntryDictionaryI"), appkit_flags);
438   AddCXXSummary(objc_category_sp,
439                 lldb_private::formatters::NSDictionarySummaryProvider<false>,
440                 "NSDictionary summary provider", ConstString("__NSDictionaryM"),
441                 appkit_flags);
442   AddCXXSummary(objc_category_sp,
443                 lldb_private::formatters::NSDictionarySummaryProvider<true>,
444                 "NSDictionary summary provider", ConstString("CFDictionaryRef"),
445                 appkit_flags);
446   AddCXXSummary(objc_category_sp,
447                 lldb_private::formatters::NSDictionarySummaryProvider<true>,
448                 "NSDictionary summary provider",
449                 ConstString("CFMutableDictionaryRef"), appkit_flags);
450 
451   AddCXXSummary(objc_category_sp,
452                 lldb_private::formatters::NSSetSummaryProvider<false>,
453                 "NSSet summary", ConstString("NSSet"), appkit_flags);
454   AddCXXSummary(
455       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>,
456       "NSMutableSet summary", ConstString("NSMutableSet"), appkit_flags);
457   AddCXXSummary(objc_category_sp,
458                 lldb_private::formatters::NSSetSummaryProvider<true>,
459                 "CFSetRef summary", ConstString("CFSetRef"), appkit_flags);
460   AddCXXSummary(
461       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<true>,
462       "CFMutableSetRef summary", ConstString("CFMutableSetRef"), appkit_flags);
463   AddCXXSummary(objc_category_sp,
464                 lldb_private::formatters::NSSetSummaryProvider<false>,
465                 "__NSCFSet summary", ConstString("__NSCFSet"), appkit_flags);
466   AddCXXSummary(objc_category_sp,
467                 lldb_private::formatters::NSSetSummaryProvider<false>,
468                 "__NSSetI summary", ConstString("__NSSetI"), appkit_flags);
469   AddCXXSummary(objc_category_sp,
470                 lldb_private::formatters::NSSetSummaryProvider<false>,
471                 "__NSSetM summary", ConstString("__NSSetM"), appkit_flags);
472   AddCXXSummary(
473       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>,
474       "NSCountedSet summary", ConstString("NSCountedSet"), appkit_flags);
475   AddCXXSummary(
476       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>,
477       "NSMutableSet summary", ConstString("NSMutableSet"), appkit_flags);
478   AddCXXSummary(
479       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>,
480       "NSOrderedSet summary", ConstString("NSOrderedSet"), appkit_flags);
481   AddCXXSummary(
482       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>,
483       "__NSOrderedSetI summary", ConstString("__NSOrderedSetI"), appkit_flags);
484   AddCXXSummary(
485       objc_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>,
486       "__NSOrderedSetM summary", ConstString("__NSOrderedSetM"), appkit_flags);
487 
488   AddCXXSummary(
489       objc_category_sp, lldb_private::formatters::NSError_SummaryProvider,
490       "NSError summary provider", ConstString("NSError"), appkit_flags);
491   AddCXXSummary(
492       objc_category_sp, lldb_private::formatters::NSException_SummaryProvider,
493       "NSException summary provider", ConstString("NSException"), appkit_flags);
494 
495   // AddSummary(appkit_category_sp, "${var.key%@} -> ${var.value%@}",
496   // ConstString("$_lldb_typegen_nspair"), appkit_flags);
497 
498   appkit_flags.SetDontShowChildren(true);
499 
500   AddCXXSynthetic(objc_category_sp,
501                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
502                   "NSArray synthetic children", ConstString("__NSArrayM"),
503                   ScriptedSyntheticChildren::Flags());
504   AddCXXSynthetic(objc_category_sp,
505                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
506                   "NSArray synthetic children", ConstString("__NSArrayI"),
507                   ScriptedSyntheticChildren::Flags());
508   AddCXXSynthetic(objc_category_sp,
509                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
510                   "NSArray synthetic children", ConstString("__NSArray0"),
511                   ScriptedSyntheticChildren::Flags());
512   AddCXXSynthetic(objc_category_sp,
513                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
514                   "NSArray synthetic children",
515                   ConstString("__NSSingleObjectArrayI"),
516                   ScriptedSyntheticChildren::Flags());
517   AddCXXSynthetic(objc_category_sp,
518                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
519                   "NSArray synthetic children", ConstString("NSArray"),
520                   ScriptedSyntheticChildren::Flags());
521   AddCXXSynthetic(objc_category_sp,
522                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
523                   "NSArray synthetic children", ConstString("NSMutableArray"),
524                   ScriptedSyntheticChildren::Flags());
525   AddCXXSynthetic(objc_category_sp,
526                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
527                   "NSArray synthetic children", ConstString("__NSCFArray"),
528                   ScriptedSyntheticChildren::Flags());
529   AddCXXSynthetic(objc_category_sp,
530                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
531                   "NSArray synthetic children", ConstString("_NSCallStackArray"),
532                   ScriptedSyntheticChildren::Flags());
533   AddCXXSynthetic(objc_category_sp,
534                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
535                   "NSArray synthetic children",
536                   ConstString("CFMutableArrayRef"),
537                   ScriptedSyntheticChildren::Flags());
538   AddCXXSynthetic(objc_category_sp,
539                   lldb_private::formatters::NSArraySyntheticFrontEndCreator,
540                   "NSArray synthetic children", ConstString("CFArrayRef"),
541                   ScriptedSyntheticChildren::Flags());
542 
543   AddCXXSynthetic(
544       objc_category_sp,
545       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
546       "NSDictionary synthetic children", ConstString("__NSDictionaryM"),
547       ScriptedSyntheticChildren::Flags());
548   AddCXXSynthetic(
549       objc_category_sp,
550       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
551       "NSDictionary synthetic children", ConstString("__NSDictionaryI"),
552       ScriptedSyntheticChildren::Flags());
553   AddCXXSynthetic(
554       objc_category_sp,
555       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
556       "NSDictionary synthetic children",
557       ConstString("__NSSingleEntryDictionaryI"),
558       ScriptedSyntheticChildren::Flags());
559   AddCXXSynthetic(
560       objc_category_sp,
561       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
562       "NSDictionary synthetic children", ConstString("__NSCFDictionary"),
563       ScriptedSyntheticChildren::Flags());
564   AddCXXSynthetic(
565       objc_category_sp,
566       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
567       "NSDictionary synthetic children", ConstString("NSDictionary"),
568       ScriptedSyntheticChildren::Flags());
569   AddCXXSynthetic(
570       objc_category_sp,
571       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
572       "NSDictionary synthetic children", ConstString("NSMutableDictionary"),
573       ScriptedSyntheticChildren::Flags());
574   AddCXXSynthetic(
575       objc_category_sp,
576       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
577       "NSDictionary synthetic children", ConstString("CFDictionaryRef"),
578       ScriptedSyntheticChildren::Flags());
579   AddCXXSynthetic(
580       objc_category_sp,
581       lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
582       "NSDictionary synthetic children", ConstString("CFMutableDictionaryRef"),
583       ScriptedSyntheticChildren::Flags());
584 
585   AddCXXSynthetic(objc_category_sp,
586                   lldb_private::formatters::NSErrorSyntheticFrontEndCreator,
587                   "NSError synthetic children", ConstString("NSError"),
588                   ScriptedSyntheticChildren::Flags());
589   AddCXXSynthetic(objc_category_sp,
590                   lldb_private::formatters::NSExceptionSyntheticFrontEndCreator,
591                   "NSException synthetic children", ConstString("NSException"),
592                   ScriptedSyntheticChildren::Flags());
593 
594   AddCXXSynthetic(objc_category_sp,
595                   lldb_private::formatters::NSSetSyntheticFrontEndCreator,
596                   "NSSet synthetic children", ConstString("NSSet"),
597                   ScriptedSyntheticChildren::Flags());
598   AddCXXSynthetic(objc_category_sp,
599                   lldb_private::formatters::NSSetSyntheticFrontEndCreator,
600                   "__NSSetI synthetic children", ConstString("__NSSetI"),
601                   ScriptedSyntheticChildren::Flags());
602   AddCXXSynthetic(objc_category_sp,
603                   lldb_private::formatters::NSSetSyntheticFrontEndCreator,
604                   "__NSSetM synthetic children", ConstString("__NSSetM"),
605                   ScriptedSyntheticChildren::Flags());
606   AddCXXSynthetic(
607       objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
608       "NSMutableSet synthetic children", ConstString("NSMutableSet"),
609       ScriptedSyntheticChildren::Flags());
610   AddCXXSynthetic(
611       objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
612       "NSOrderedSet synthetic children", ConstString("NSOrderedSet"),
613       ScriptedSyntheticChildren::Flags());
614   AddCXXSynthetic(
615       objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
616       "__NSOrderedSetI synthetic children", ConstString("__NSOrderedSetI"),
617       ScriptedSyntheticChildren::Flags());
618   AddCXXSynthetic(
619       objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
620       "__NSOrderedSetM synthetic children", ConstString("__NSOrderedSetM"),
621       ScriptedSyntheticChildren::Flags());
622 
623   AddCXXSynthetic(objc_category_sp,
624                   lldb_private::formatters::NSIndexPathSyntheticFrontEndCreator,
625                   "NSIndexPath synthetic children", ConstString("NSIndexPath"),
626                   ScriptedSyntheticChildren::Flags());
627 
628   AddCXXSummary(
629       objc_category_sp, lldb_private::formatters::CFBagSummaryProvider,
630       "CFBag summary provider", ConstString("CFBagRef"), appkit_flags);
631   AddCXXSummary(objc_category_sp,
632                 lldb_private::formatters::CFBagSummaryProvider,
633                 "CFBag summary provider", ConstString("__CFBag"), appkit_flags);
634   AddCXXSummary(objc_category_sp,
635                 lldb_private::formatters::CFBagSummaryProvider,
636                 "CFBag summary provider", ConstString("const struct __CFBag"),
637                 appkit_flags);
638   AddCXXSummary(
639       objc_category_sp, lldb_private::formatters::CFBagSummaryProvider,
640       "CFBag summary provider", ConstString("CFMutableBagRef"), appkit_flags);
641 
642   AddCXXSummary(objc_category_sp,
643                 lldb_private::formatters::CFBinaryHeapSummaryProvider,
644                 "CFBinaryHeap summary provider", ConstString("CFBinaryHeapRef"),
645                 appkit_flags);
646   AddCXXSummary(objc_category_sp,
647                 lldb_private::formatters::CFBinaryHeapSummaryProvider,
648                 "CFBinaryHeap summary provider", ConstString("__CFBinaryHeap"),
649                 appkit_flags);
650 
651   AddCXXSummary(
652       objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
653       "NSString summary provider", ConstString("NSString"), appkit_flags);
654   AddCXXSummary(
655       objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
656       "NSString summary provider", ConstString("CFStringRef"), appkit_flags);
657   AddCXXSummary(
658       objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
659       "NSString summary provider", ConstString("__CFString"), appkit_flags);
660   AddCXXSummary(objc_category_sp,
661                 lldb_private::formatters::NSStringSummaryProvider,
662                 "NSString summary provider", ConstString("CFMutableStringRef"),
663                 appkit_flags);
664   AddCXXSummary(objc_category_sp,
665                 lldb_private::formatters::NSStringSummaryProvider,
666                 "NSString summary provider", ConstString("NSMutableString"),
667                 appkit_flags);
668   AddCXXSummary(objc_category_sp,
669                 lldb_private::formatters::NSStringSummaryProvider,
670                 "NSString summary provider",
671                 ConstString("__NSCFConstantString"), appkit_flags);
672   AddCXXSummary(
673       objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
674       "NSString summary provider", ConstString("__NSCFString"), appkit_flags);
675   AddCXXSummary(objc_category_sp,
676                 lldb_private::formatters::NSStringSummaryProvider,
677                 "NSString summary provider", ConstString("NSCFConstantString"),
678                 appkit_flags);
679   AddCXXSummary(
680       objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
681       "NSString summary provider", ConstString("NSCFString"), appkit_flags);
682   AddCXXSummary(
683       objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
684       "NSString summary provider", ConstString("NSPathStore2"), appkit_flags);
685   AddCXXSummary(objc_category_sp,
686                 lldb_private::formatters::NSStringSummaryProvider,
687                 "NSString summary provider",
688                 ConstString("NSTaggedPointerString"), appkit_flags);
689 
690   AddCXXSummary(objc_category_sp,
691                 lldb_private::formatters::NSAttributedStringSummaryProvider,
692                 "NSAttributedString summary provider",
693                 ConstString("NSAttributedString"), appkit_flags);
694   AddCXXSummary(
695       objc_category_sp,
696       lldb_private::formatters::NSMutableAttributedStringSummaryProvider,
697       "NSMutableAttributedString summary provider",
698       ConstString("NSMutableAttributedString"), appkit_flags);
699   AddCXXSummary(
700       objc_category_sp,
701       lldb_private::formatters::NSMutableAttributedStringSummaryProvider,
702       "NSMutableAttributedString summary provider",
703       ConstString("NSConcreteMutableAttributedString"), appkit_flags);
704 
705   AddCXXSummary(
706       objc_category_sp, lldb_private::formatters::NSBundleSummaryProvider,
707       "NSBundle summary provider", ConstString("NSBundle"), appkit_flags);
708 
709   AddCXXSummary(objc_category_sp,
710                 lldb_private::formatters::NSDataSummaryProvider<false>,
711                 "NSData summary provider", ConstString("NSData"), appkit_flags);
712   AddCXXSummary(
713       objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>,
714       "NSData summary provider", ConstString("_NSInlineData"), appkit_flags);
715   AddCXXSummary(
716       objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>,
717       "NSData summary provider", ConstString("NSConcreteData"), appkit_flags);
718   AddCXXSummary(objc_category_sp,
719                 lldb_private::formatters::NSDataSummaryProvider<false>,
720                 "NSData summary provider", ConstString("NSConcreteMutableData"),
721                 appkit_flags);
722   AddCXXSummary(
723       objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>,
724       "NSData summary provider", ConstString("NSMutableData"), appkit_flags);
725   AddCXXSummary(
726       objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>,
727       "NSData summary provider", ConstString("__NSCFData"), appkit_flags);
728   AddCXXSummary(
729       objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<true>,
730       "NSData summary provider", ConstString("CFDataRef"), appkit_flags);
731   AddCXXSummary(
732       objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<true>,
733       "NSData summary provider", ConstString("CFMutableDataRef"), appkit_flags);
734 
735   AddCXXSummary(
736       objc_category_sp, lldb_private::formatters::NSMachPortSummaryProvider,
737       "NSMachPort summary provider", ConstString("NSMachPort"), appkit_flags);
738 
739   AddCXXSummary(objc_category_sp,
740                 lldb_private::formatters::NSNotificationSummaryProvider,
741                 "NSNotification summary provider",
742                 ConstString("NSNotification"), appkit_flags);
743   AddCXXSummary(objc_category_sp,
744                 lldb_private::formatters::NSNotificationSummaryProvider,
745                 "NSNotification summary provider",
746                 ConstString("NSConcreteNotification"), appkit_flags);
747 
748   AddCXXSummary(
749       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
750       "NSNumber summary provider", ConstString("NSNumber"), appkit_flags);
751   AddCXXSummary(
752       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
753       "CFNumberRef summary provider", ConstString("CFNumberRef"), appkit_flags);
754   AddCXXSummary(
755       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
756       "NSNumber summary provider", ConstString("__NSCFBoolean"), appkit_flags);
757   AddCXXSummary(
758       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
759       "NSNumber summary provider", ConstString("__NSCFNumber"), appkit_flags);
760   AddCXXSummary(
761       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
762       "NSNumber summary provider", ConstString("NSCFBoolean"), appkit_flags);
763   AddCXXSummary(
764       objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
765       "NSNumber summary provider", ConstString("NSCFNumber"), appkit_flags);
766   AddCXXSummary(objc_category_sp,
767                 lldb_private::formatters::NSNumberSummaryProvider,
768                 "NSDecimalNumber summary provider",
769                 ConstString("NSDecimalNumber"), appkit_flags);
770 
771   AddCXXSummary(objc_category_sp,
772                 lldb_private::formatters::NSURLSummaryProvider,
773                 "NSURL summary provider", ConstString("NSURL"), appkit_flags);
774   AddCXXSummary(
775       objc_category_sp, lldb_private::formatters::NSURLSummaryProvider,
776       "NSURL summary provider", ConstString("CFURLRef"), appkit_flags);
777 
778   AddCXXSummary(objc_category_sp,
779                 lldb_private::formatters::NSDateSummaryProvider,
780                 "NSDate summary provider", ConstString("NSDate"), appkit_flags);
781   AddCXXSummary(
782       objc_category_sp, lldb_private::formatters::NSDateSummaryProvider,
783       "NSDate summary provider", ConstString("__NSDate"), appkit_flags);
784   AddCXXSummary(
785       objc_category_sp, lldb_private::formatters::NSDateSummaryProvider,
786       "NSDate summary provider", ConstString("__NSTaggedDate"), appkit_flags);
787   AddCXXSummary(
788       objc_category_sp, lldb_private::formatters::NSDateSummaryProvider,
789       "NSDate summary provider", ConstString("NSCalendarDate"), appkit_flags);
790 
791   AddCXXSummary(
792       objc_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider,
793       "NSTimeZone summary provider", ConstString("NSTimeZone"), appkit_flags);
794   AddCXXSummary(objc_category_sp,
795                 lldb_private::formatters::NSTimeZoneSummaryProvider,
796                 "NSTimeZone summary provider", ConstString("CFTimeZoneRef"),
797                 appkit_flags);
798   AddCXXSummary(
799       objc_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider,
800       "NSTimeZone summary provider", ConstString("__NSTimeZone"), appkit_flags);
801 
802   // CFAbsoluteTime is actually a double rather than a pointer to an object we
803   // do not care about the numeric value, since it is probably meaningless to
804   // users
805   appkit_flags.SetDontShowValue(true);
806   AddCXXSummary(objc_category_sp,
807                 lldb_private::formatters::CFAbsoluteTimeSummaryProvider,
808                 "CFAbsoluteTime summary provider",
809                 ConstString("CFAbsoluteTime"), appkit_flags);
810   appkit_flags.SetDontShowValue(false);
811 
812   AddCXXSummary(
813       objc_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider,
814       "NSIndexSet summary provider", ConstString("NSIndexSet"), appkit_flags);
815   AddCXXSummary(objc_category_sp,
816                 lldb_private::formatters::NSIndexSetSummaryProvider,
817                 "NSIndexSet summary provider", ConstString("NSMutableIndexSet"),
818                 appkit_flags);
819 
820   AddStringSummary(objc_category_sp,
821                    "@\"${var.month%d}/${var.day%d}/${var.year%d} "
822                    "${var.hour%d}:${var.minute%d}:${var.second}\"",
823                    ConstString("CFGregorianDate"), appkit_flags);
824 
825   AddCXXSummary(objc_category_sp,
826                 lldb_private::formatters::CFBitVectorSummaryProvider,
827                 "CFBitVector summary provider", ConstString("CFBitVectorRef"),
828                 appkit_flags);
829   AddCXXSummary(objc_category_sp,
830                 lldb_private::formatters::CFBitVectorSummaryProvider,
831                 "CFBitVector summary provider",
832                 ConstString("CFMutableBitVectorRef"), appkit_flags);
833   AddCXXSummary(objc_category_sp,
834                 lldb_private::formatters::CFBitVectorSummaryProvider,
835                 "CFBitVector summary provider", ConstString("__CFBitVector"),
836                 appkit_flags);
837   AddCXXSummary(objc_category_sp,
838                 lldb_private::formatters::CFBitVectorSummaryProvider,
839                 "CFBitVector summary provider",
840                 ConstString("__CFMutableBitVector"), appkit_flags);
841 }
842 
843 static void LoadCoreMediaFormatters(TypeCategoryImplSP objc_category_sp) {
844   if (!objc_category_sp)
845     return;
846 
847   TypeSummaryImpl::Flags cm_flags;
848   cm_flags.SetCascades(true)
849       .SetDontShowChildren(false)
850       .SetDontShowValue(false)
851       .SetHideItemNames(false)
852       .SetShowMembersOneLiner(false)
853       .SetSkipPointers(false)
854       .SetSkipReferences(false);
855 
856   AddCXXSummary(objc_category_sp,
857                 lldb_private::formatters::CMTimeSummaryProvider,
858                 "CMTime summary provider", ConstString("CMTime"), cm_flags);
859 }
860 
861 lldb::TypeCategoryImplSP ObjCLanguage::GetFormatters() {
862   static llvm::once_flag g_initialize;
863   static TypeCategoryImplSP g_category;
864 
865   llvm::call_once(g_initialize, [this]() -> void {
866     DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
867     if (g_category) {
868       LoadCoreMediaFormatters(g_category);
869       LoadObjCFormatters(g_category);
870     }
871   });
872   return g_category;
873 }
874 
875 std::vector<ConstString>
876 ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj,
877                                            lldb::DynamicValueType use_dynamic) {
878   std::vector<ConstString> result;
879 
880   if (use_dynamic == lldb::eNoDynamicValues)
881     return result;
882 
883   CompilerType compiler_type(valobj.GetCompilerType());
884 
885   const bool check_cpp = false;
886   const bool check_objc = true;
887   bool canBeObjCDynamic =
888       compiler_type.IsPossibleDynamicType(nullptr, check_cpp, check_objc);
889 
890   if (canBeObjCDynamic) {
891     do {
892       lldb::ProcessSP process_sp = valobj.GetProcessSP();
893       if (!process_sp)
894         break;
895       ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
896       if (runtime == nullptr)
897         break;
898       ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
899           runtime->GetClassDescriptor(valobj));
900       if (!objc_class_sp)
901         break;
902       if (ConstString name = objc_class_sp->GetClassName())
903         result.push_back(name);
904     } while (false);
905   }
906 
907   return result;
908 }
909 
910 std::unique_ptr<Language::TypeScavenger> ObjCLanguage::GetTypeScavenger() {
911   class ObjCScavengerResult : public Language::TypeScavenger::Result {
912   public:
913     ObjCScavengerResult(CompilerType type)
914         : Language::TypeScavenger::Result(), m_compiler_type(type) {}
915 
916     bool IsValid() override { return m_compiler_type.IsValid(); }
917 
918     bool DumpToStream(Stream &stream, bool print_help_if_available) override {
919       if (IsValid()) {
920         m_compiler_type.DumpTypeDescription(&stream);
921         stream.EOL();
922         return true;
923       }
924       return false;
925     }
926 
927   private:
928     CompilerType m_compiler_type;
929   };
930 
931   class ObjCRuntimeScavenger : public Language::TypeScavenger {
932   protected:
933     bool Find_Impl(ExecutionContextScope *exe_scope, const char *key,
934                    ResultSet &results) override {
935       bool result = false;
936 
937       if (auto *process = exe_scope->CalculateProcess().get()) {
938         if (auto *objc_runtime = ObjCLanguageRuntime::Get(*process)) {
939           if (auto *decl_vendor = objc_runtime->GetDeclVendor()) {
940             ConstString name(key);
941             for (const CompilerType &type :
942                  decl_vendor->FindTypes(name, /*max_matches*/ UINT32_MAX)) {
943               result = true;
944               std::unique_ptr<Language::TypeScavenger::Result> result(
945                   new ObjCScavengerResult(type));
946               results.insert(std::move(result));
947             }
948           }
949         }
950       }
951 
952       return result;
953     }
954 
955     friend class lldb_private::ObjCLanguage;
956   };
957 
958   class ObjCModulesScavenger : public Language::TypeScavenger {
959   protected:
960     bool Find_Impl(ExecutionContextScope *exe_scope, const char *key,
961                    ResultSet &results) override {
962       bool result = false;
963 
964       if (auto *target = exe_scope->CalculateTarget().get()) {
965         if (auto *clang_modules_decl_vendor =
966                 target->GetClangModulesDeclVendor()) {
967           ConstString key_cs(key);
968           auto types = clang_modules_decl_vendor->FindTypes(
969               key_cs, /*max_matches*/ UINT32_MAX);
970           if (!types.empty()) {
971             result = true;
972             std::unique_ptr<Language::TypeScavenger::Result> result(
973                 new ObjCScavengerResult(types.front()));
974             results.insert(std::move(result));
975           }
976         }
977       }
978 
979       return result;
980     }
981 
982     friend class lldb_private::ObjCLanguage;
983   };
984 
985   class ObjCDebugInfoScavenger : public Language::ImageListTypeScavenger {
986   public:
987     CompilerType AdjustForInclusion(CompilerType &candidate) override {
988       LanguageType lang_type(candidate.GetMinimumLanguage());
989       if (!Language::LanguageIsObjC(lang_type))
990         return CompilerType();
991       if (candidate.IsTypedefType())
992         return candidate.GetTypedefedType();
993       return candidate;
994     }
995   };
996 
997   return std::unique_ptr<TypeScavenger>(
998       new Language::EitherTypeScavenger<ObjCModulesScavenger,
999                                         ObjCRuntimeScavenger,
1000                                         ObjCDebugInfoScavenger>());
1001 }
1002 
1003 bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
1004                                             ConstString type_hint,
1005                                             std::string &prefix,
1006                                             std::string &suffix) {
1007   static ConstString g_CFBag("CFBag");
1008   static ConstString g_CFBinaryHeap("CFBinaryHeap");
1009 
1010   static ConstString g_NSNumberChar("NSNumber:char");
1011   static ConstString g_NSNumberShort("NSNumber:short");
1012   static ConstString g_NSNumberInt("NSNumber:int");
1013   static ConstString g_NSNumberLong("NSNumber:long");
1014   static ConstString g_NSNumberInt128("NSNumber:int128_t");
1015   static ConstString g_NSNumberFloat("NSNumber:float");
1016   static ConstString g_NSNumberDouble("NSNumber:double");
1017 
1018   static ConstString g_NSData("NSData");
1019   static ConstString g_NSArray("NSArray");
1020   static ConstString g_NSString("NSString");
1021   static ConstString g_NSStringStar("NSString*");
1022 
1023   if (type_hint.IsEmpty())
1024     return false;
1025 
1026   prefix.clear();
1027   suffix.clear();
1028 
1029   if (type_hint == g_CFBag || type_hint == g_CFBinaryHeap) {
1030     prefix = "@";
1031     return true;
1032   }
1033 
1034   if (type_hint == g_NSNumberChar) {
1035     prefix = "(char)";
1036     return true;
1037   }
1038   if (type_hint == g_NSNumberShort) {
1039     prefix = "(short)";
1040     return true;
1041   }
1042   if (type_hint == g_NSNumberInt) {
1043     prefix = "(int)";
1044     return true;
1045   }
1046   if (type_hint == g_NSNumberLong) {
1047     prefix = "(long)";
1048     return true;
1049   }
1050   if (type_hint == g_NSNumberInt128) {
1051     prefix = "(int128_t)";
1052     return true;
1053   }
1054   if (type_hint == g_NSNumberFloat) {
1055     prefix = "(float)";
1056     return true;
1057   }
1058   if (type_hint == g_NSNumberDouble) {
1059     prefix = "(double)";
1060     return true;
1061   }
1062 
1063   if (type_hint == g_NSData || type_hint == g_NSArray) {
1064     prefix = "@\"";
1065     suffix = "\"";
1066     return true;
1067   }
1068 
1069   if (type_hint == g_NSString || type_hint == g_NSStringStar) {
1070     prefix = "@";
1071     return true;
1072   }
1073 
1074   return false;
1075 }
1076 
1077 bool ObjCLanguage::IsNilReference(ValueObject &valobj) {
1078   const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
1079   bool isObjCpointer =
1080       (((valobj.GetCompilerType().GetTypeInfo(nullptr)) & mask) == mask);
1081   if (!isObjCpointer)
1082     return false;
1083   bool canReadValue = true;
1084   bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
1085   return canReadValue && isZero;
1086 }
1087 
1088 bool ObjCLanguage::IsSourceFile(llvm::StringRef file_path) const {
1089   const auto suffixes = {".h", ".m", ".M"};
1090   for (auto suffix : suffixes) {
1091     if (file_path.endswith_lower(suffix))
1092       return true;
1093   }
1094   return false;
1095 }
1096