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