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