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