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