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