1 //===-- AppleObjCDeclVendor.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 "AppleObjCDeclVendor.h"
10 
11 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Symbol/ClangASTMetadata.h"
14 #include "lldb/Symbol/ClangUtil.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/Log.h"
18 
19 #include "clang/AST/ASTContext.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/ExternalASTSource.h"
22 
23 using namespace lldb_private;
24 
25 class lldb_private::AppleObjCExternalASTSource
26     : public clang::ExternalASTSource {
27 public:
28   AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)
29       : m_decl_vendor(decl_vendor) {}
30 
31   bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx,
32                                       clang::DeclarationName name) override {
33     static unsigned int invocation_id = 0;
34     unsigned int current_id = invocation_id++;
35 
36     Log *log(GetLogIfAllCategoriesSet(
37         LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
38 
39     if (log) {
40       LLDB_LOGF(log,
41                 "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%"
42                 "u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
43                 current_id,
44                 static_cast<void *>(&decl_ctx->getParentASTContext()),
45                 name.getAsString().c_str(), decl_ctx->getDeclKindName(),
46                 static_cast<const void *>(decl_ctx));
47     }
48 
49     do {
50       const clang::ObjCInterfaceDecl *interface_decl =
51           llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
52 
53       if (!interface_decl)
54         break;
55 
56       clang::ObjCInterfaceDecl *non_const_interface_decl =
57           const_cast<clang::ObjCInterfaceDecl *>(interface_decl);
58 
59       if (!m_decl_vendor.FinishDecl(non_const_interface_decl))
60         break;
61 
62       clang::DeclContext::lookup_result result =
63           non_const_interface_decl->lookup(name);
64 
65       return (result.size() != 0);
66     } while (false);
67 
68     SetNoExternalVisibleDeclsForName(decl_ctx, name);
69     return false;
70   }
71 
72   void CompleteType(clang::TagDecl *tag_decl) override {
73     static unsigned int invocation_id = 0;
74     unsigned int current_id = invocation_id++;
75 
76     Log *log(GetLogIfAllCategoriesSet(
77         LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
78 
79     LLDB_LOGF(log,
80               "AppleObjCExternalASTSource::CompleteType[%u] on "
81               "(ASTContext*)%p Completing (TagDecl*)%p named %s",
82               current_id, static_cast<void *>(&tag_decl->getASTContext()),
83               static_cast<void *>(tag_decl), tag_decl->getName().str().c_str());
84 
85     LLDB_LOG(log, "  AOEAS::CT[{0}] Before:\n{1}", current_id,
86              ClangUtil::DumpDecl(tag_decl));
87 
88     LLDB_LOG(log, "  AOEAS::CT[{1}] After:{1}", current_id,
89              ClangUtil::DumpDecl(tag_decl));
90 
91     return;
92   }
93 
94   void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override {
95     static unsigned int invocation_id = 0;
96     unsigned int current_id = invocation_id++;
97 
98     Log *log(GetLogIfAllCategoriesSet(
99         LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
100 
101     if (log) {
102       LLDB_LOGF(log,
103                 "AppleObjCExternalASTSource::CompleteType[%u] on "
104                 "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
105                 current_id,
106                 static_cast<void *>(&interface_decl->getASTContext()),
107                 static_cast<void *>(interface_decl),
108                 interface_decl->getName().str().c_str());
109 
110       LLDB_LOGF(log, "  AOEAS::CT[%u] Before:", current_id);
111       LLDB_LOG(log, "    [CT] {0}", ClangUtil::DumpDecl(interface_decl));
112     }
113 
114     m_decl_vendor.FinishDecl(interface_decl);
115 
116     if (log) {
117       LLDB_LOGF(log, "  [CT] After:");
118       LLDB_LOG(log, "    [CT] {0}", ClangUtil::DumpDecl(interface_decl));
119     }
120     return;
121   }
122 
123   bool layoutRecordType(
124       const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
125       llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
126       llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
127           &BaseOffsets,
128       llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
129           &VirtualBaseOffsets) override {
130     return false;
131   }
132 
133   void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
134     clang::TranslationUnitDecl *translation_unit_decl =
135         m_decl_vendor.m_ast_ctx.getASTContext().getTranslationUnitDecl();
136     translation_unit_decl->setHasExternalVisibleStorage();
137     translation_unit_decl->setHasExternalLexicalStorage();
138   }
139 
140 private:
141   AppleObjCDeclVendor &m_decl_vendor;
142 };
143 
144 AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime)
145     : ClangDeclVendor(eAppleObjCDeclVendor), m_runtime(runtime),
146       m_ast_ctx(runtime.GetProcess()
147                     ->GetTarget()
148                     .GetArchitecture()
149                     .GetTriple()),
150       m_type_realizer_sp(m_runtime.GetEncodingToType()) {
151   m_external_source = new AppleObjCExternalASTSource(*this);
152   llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr(
153       m_external_source);
154   m_ast_ctx.getASTContext().setExternalSource(external_source_owning_ptr);
155 }
156 
157 clang::ObjCInterfaceDecl *
158 AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) {
159   ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
160 
161   if (iter != m_isa_to_interface.end())
162     return iter->second;
163 
164   clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext();
165 
166   ObjCLanguageRuntime::ClassDescriptorSP descriptor =
167       m_runtime.GetClassDescriptorFromISA(isa);
168 
169   if (!descriptor)
170     return nullptr;
171 
172   ConstString name(descriptor->GetClassName());
173 
174   clang::IdentifierInfo &identifier_info =
175       ast_ctx.Idents.get(name.GetStringRef());
176 
177   clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(
178       ast_ctx, ast_ctx.getTranslationUnitDecl(), clang::SourceLocation(),
179       &identifier_info, nullptr, nullptr);
180 
181   ClangASTMetadata meta_data;
182   meta_data.SetISAPtr(isa);
183   m_ast_ctx.SetMetadata(new_iface_decl, meta_data);
184 
185   new_iface_decl->setHasExternalVisibleStorage();
186   new_iface_decl->setHasExternalLexicalStorage();
187 
188   ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl);
189 
190   m_isa_to_interface[isa] = new_iface_decl;
191 
192   return new_iface_decl;
193 }
194 
195 class ObjCRuntimeMethodType {
196 public:
197   ObjCRuntimeMethodType(const char *types) : m_is_valid(false) {
198     const char *cursor = types;
199     enum ParserState { Start = 0, InType, InPos } state = Start;
200     const char *type = nullptr;
201     int brace_depth = 0;
202 
203     uint32_t stepsLeft = 256;
204 
205     while (true) {
206       if (--stepsLeft == 0) {
207         m_is_valid = false;
208         return;
209       }
210 
211       switch (state) {
212       case Start: {
213         switch (*cursor) {
214         default:
215           state = InType;
216           type = cursor;
217           break;
218         case '\0':
219           m_is_valid = true;
220           return;
221         case '0':
222         case '1':
223         case '2':
224         case '3':
225         case '4':
226         case '5':
227         case '6':
228         case '7':
229         case '8':
230         case '9':
231           m_is_valid = false;
232           return;
233         }
234       } break;
235       case InType: {
236         switch (*cursor) {
237         default:
238           ++cursor;
239           break;
240         case '0':
241         case '1':
242         case '2':
243         case '3':
244         case '4':
245         case '5':
246         case '6':
247         case '7':
248         case '8':
249         case '9':
250           if (!brace_depth) {
251             state = InPos;
252             if (type) {
253               m_type_vector.push_back(std::string(type, (cursor - type)));
254             } else {
255               m_is_valid = false;
256               return;
257             }
258             type = nullptr;
259           } else {
260             ++cursor;
261           }
262           break;
263         case '[':
264         case '{':
265         case '(':
266           ++brace_depth;
267           ++cursor;
268           break;
269         case ']':
270         case '}':
271         case ')':
272           if (!brace_depth) {
273             m_is_valid = false;
274             return;
275           }
276           --brace_depth;
277           ++cursor;
278           break;
279         case '\0':
280           m_is_valid = false;
281           return;
282         }
283       } break;
284       case InPos: {
285         switch (*cursor) {
286         default:
287           state = InType;
288           type = cursor;
289           break;
290         case '0':
291         case '1':
292         case '2':
293         case '3':
294         case '4':
295         case '5':
296         case '6':
297         case '7':
298         case '8':
299         case '9':
300           ++cursor;
301           break;
302         case '\0':
303           m_is_valid = true;
304           return;
305         }
306       } break;
307       }
308     }
309   }
310 
311   clang::ObjCMethodDecl *
312   BuildMethod(ClangASTContext &clang_ast_ctxt,
313               clang::ObjCInterfaceDecl *interface_decl, const char *name,
314               bool instance,
315               ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) {
316     if (!m_is_valid || m_type_vector.size() < 3)
317       return nullptr;
318 
319     clang::ASTContext &ast_ctx(interface_decl->getASTContext());
320 
321     const bool isInstance = instance;
322     const bool isVariadic = false;
323     const bool isPropertyAccessor = false;
324     const bool isSynthesizedAccessorStub = false;
325     const bool isImplicitlyDeclared = true;
326     const bool isDefined = false;
327     const clang::ObjCMethodDecl::ImplementationControl impControl =
328         clang::ObjCMethodDecl::None;
329     const bool HasRelatedResultType = false;
330     const bool for_expression = true;
331 
332     std::vector<clang::IdentifierInfo *> selector_components;
333 
334     const char *name_cursor = name;
335     bool is_zero_argument = true;
336 
337     while (*name_cursor != '\0') {
338       const char *colon_loc = strchr(name_cursor, ':');
339       if (!colon_loc) {
340         selector_components.push_back(
341             &ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
342         break;
343       } else {
344         is_zero_argument = false;
345         selector_components.push_back(&ast_ctx.Idents.get(
346             llvm::StringRef(name_cursor, colon_loc - name_cursor)));
347         name_cursor = colon_loc + 1;
348       }
349     }
350 
351     clang::IdentifierInfo **identifier_infos = selector_components.data();
352     if (!identifier_infos) {
353       return nullptr;
354     }
355 
356     clang::Selector sel = ast_ctx.Selectors.getSelector(
357         is_zero_argument ? 0 : selector_components.size(),
358         identifier_infos);
359 
360     clang::QualType ret_type =
361         ClangUtil::GetQualType(type_realizer_sp->RealizeType(
362             clang_ast_ctxt, m_type_vector[0].c_str(), for_expression));
363 
364     if (ret_type.isNull())
365       return nullptr;
366 
367     clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(
368         ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel,
369         ret_type, nullptr, interface_decl, isInstance, isVariadic,
370         isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,
371         isDefined, impControl, HasRelatedResultType);
372 
373     std::vector<clang::ParmVarDecl *> parm_vars;
374 
375     for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) {
376       const bool for_expression = true;
377       clang::QualType arg_type =
378           ClangUtil::GetQualType(type_realizer_sp->RealizeType(
379               clang_ast_ctxt, m_type_vector[ai].c_str(), for_expression));
380 
381       if (arg_type.isNull())
382         return nullptr; // well, we just wasted a bunch of time.  Wish we could
383                         // delete the stuff we'd just made!
384 
385       parm_vars.push_back(clang::ParmVarDecl::Create(
386           ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(),
387           nullptr, arg_type, nullptr, clang::SC_None, nullptr));
388     }
389 
390     ret->setMethodParams(ast_ctx,
391                          llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars),
392                          llvm::ArrayRef<clang::SourceLocation>());
393 
394     return ret;
395   }
396 
397   explicit operator bool() { return m_is_valid; }
398 
399   size_t GetNumTypes() { return m_type_vector.size(); }
400 
401   const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); }
402 
403 private:
404   typedef std::vector<std::string> TypeVector;
405 
406   TypeVector m_type_vector;
407   bool m_is_valid;
408 };
409 
410 bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {
411   Log *log(GetLogIfAllCategoriesSet(
412       LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
413 
414   ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(interface_decl);
415   ObjCLanguageRuntime::ObjCISA objc_isa = 0;
416   if (metadata)
417     objc_isa = metadata->GetISAPtr();
418 
419   if (!objc_isa)
420     return false;
421 
422   if (!interface_decl->hasExternalVisibleStorage())
423     return true;
424 
425   interface_decl->startDefinition();
426 
427   interface_decl->setHasExternalVisibleStorage(false);
428   interface_decl->setHasExternalLexicalStorage(false);
429 
430   ObjCLanguageRuntime::ClassDescriptorSP descriptor =
431       m_runtime.GetClassDescriptorFromISA(objc_isa);
432 
433   if (!descriptor)
434     return false;
435 
436   auto superclass_func = [interface_decl,
437                           this](ObjCLanguageRuntime::ObjCISA isa) {
438     clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
439 
440     if (!superclass_decl)
441       return;
442 
443     FinishDecl(superclass_decl);
444     clang::ASTContext &context = m_ast_ctx.getASTContext();
445     interface_decl->setSuperClass(context.getTrivialTypeSourceInfo(
446         context.getObjCInterfaceType(superclass_decl)));
447   };
448 
449   auto instance_method_func =
450       [log, interface_decl, this](const char *name, const char *types) -> bool {
451     if (!name || !types)
452       return false; // skip this one
453 
454     ObjCRuntimeMethodType method_type(types);
455 
456     clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
457         m_ast_ctx, interface_decl, name, true, m_type_realizer_sp);
458 
459     LLDB_LOGF(log, "[  AOTV::FD] Instance method [%s] [%s]", name, types);
460 
461     if (method_decl)
462       interface_decl->addDecl(method_decl);
463 
464     return false;
465   };
466 
467   auto class_method_func = [log, interface_decl,
468                             this](const char *name, const char *types) -> bool {
469     if (!name || !types)
470       return false; // skip this one
471 
472     ObjCRuntimeMethodType method_type(types);
473 
474     clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
475         m_ast_ctx, interface_decl, name, false, m_type_realizer_sp);
476 
477     LLDB_LOGF(log, "[  AOTV::FD] Class method [%s] [%s]", name, types);
478 
479     if (method_decl)
480       interface_decl->addDecl(method_decl);
481 
482     return false;
483   };
484 
485   auto ivar_func = [log, interface_decl,
486                     this](const char *name, const char *type,
487                           lldb::addr_t offset_ptr, uint64_t size) -> bool {
488     if (!name || !type)
489       return false;
490 
491     const bool for_expression = false;
492 
493     LLDB_LOGF(log,
494               "[  AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64,
495               name, type, offset_ptr);
496 
497     CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(
498         m_ast_ctx, type, for_expression);
499 
500     if (ivar_type.IsValid()) {
501       clang::TypeSourceInfo *const type_source_info = nullptr;
502       const bool is_synthesized = false;
503       clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create(
504           m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(),
505           clang::SourceLocation(), &m_ast_ctx.getASTContext().Idents.get(name),
506           ClangUtil::GetQualType(ivar_type),
507           type_source_info, // TypeSourceInfo *
508           clang::ObjCIvarDecl::Public, nullptr, is_synthesized);
509 
510       if (ivar_decl) {
511         interface_decl->addDecl(ivar_decl);
512       }
513     }
514 
515     return false;
516   };
517 
518   LLDB_LOG(log,
519            "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C "
520            "interface for %s",
521            descriptor->GetClassName().AsCString());
522 
523   if (!descriptor->Describe(superclass_func, instance_method_func,
524                             class_method_func, ivar_func))
525     return false;
526 
527   if (log) {
528     LLDB_LOGF(
529         log,
530         "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface");
531 
532     LLDB_LOG(log, "  [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl));
533   }
534 
535   return true;
536 }
537 
538 uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append,
539                                         uint32_t max_matches,
540                                         std::vector<CompilerDecl> &decls) {
541   static unsigned int invocation_id = 0;
542   unsigned int current_id = invocation_id++;
543 
544   Log *log(GetLogIfAllCategoriesSet(
545       LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
546 
547   LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls [%u] ('%s', %s, %u, )",
548             current_id, (const char *)name.AsCString(),
549             append ? "true" : "false", max_matches);
550 
551   if (!append)
552     decls.clear();
553 
554   uint32_t ret = 0;
555 
556   do {
557     // See if the type is already in our ASTContext.
558 
559     clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext();
560 
561     clang::IdentifierInfo &identifier_info =
562         ast_ctx.Idents.get(name.GetStringRef());
563     clang::DeclarationName decl_name =
564         ast_ctx.DeclarationNames.getIdentifier(&identifier_info);
565 
566     clang::DeclContext::lookup_result lookup_result =
567         ast_ctx.getTranslationUnitDecl()->lookup(decl_name);
568 
569     if (!lookup_result.empty()) {
570       if (clang::ObjCInterfaceDecl *result_iface_decl =
571               llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) {
572         if (log) {
573           clang::QualType result_iface_type =
574               ast_ctx.getObjCInterfaceType(result_iface_decl);
575 
576           uint64_t isa_value = LLDB_INVALID_ADDRESS;
577           ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(result_iface_decl);
578           if (metadata)
579             isa_value = metadata->GetISAPtr();
580 
581           LLDB_LOG(log,
582                    "AOCTV::FT [%u] Found %s (isa 0x%" PRIx64
583                    ") in the ASTContext",
584                    current_id, result_iface_type.getAsString(), isa_value);
585         }
586 
587         decls.push_back(CompilerDecl(&m_ast_ctx, result_iface_decl));
588         ret++;
589         break;
590       } else {
591         LLDB_LOGF(log,
592                   "AOCTV::FT [%u] There's something in the ASTContext, but "
593                   "it's not something we know about",
594                   current_id);
595         break;
596       }
597     } else if (log) {
598       LLDB_LOGF(log, "AOCTV::FT [%u] Couldn't find %s in the ASTContext",
599                 current_id, name.AsCString());
600     }
601 
602     // It's not.  If it exists, we have to put it into our ASTContext.
603 
604     ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
605 
606     if (!isa) {
607       LLDB_LOGF(log, "AOCTV::FT [%u] Couldn't find the isa", current_id);
608 
609       break;
610     }
611 
612     clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
613 
614     if (!iface_decl) {
615       LLDB_LOGF(log,
616                 "AOCTV::FT [%u] Couldn't get the Objective-C interface for "
617                 "isa 0x%" PRIx64,
618                 current_id, (uint64_t)isa);
619 
620       break;
621     }
622 
623     if (log) {
624       clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl);
625 
626       LLDB_LOG(log, "AOCTV::FT [{0}] Created {1} (isa 0x{2:x})", current_id,
627                new_iface_type.getAsString(), (uint64_t)isa);
628     }
629 
630     decls.push_back(CompilerDecl(&m_ast_ctx, iface_decl));
631     ret++;
632     break;
633   } while (false);
634 
635   return ret;
636 }
637