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
24using namespace lldb_private;
25
26class lldb_private::AppleObjCExternalASTSource
27    : public clang::ExternalASTSource {
28public:
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
128private:
129  AppleObjCDeclVendor &m_decl_vendor;
130};
131
132AppleObjCDeclVendor::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
144clang::ObjCInterfaceDecl *
145AppleObjCDeclVendor::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
182class ObjCRuntimeMethodType {
183public:
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::ObjCImplementationControl impControl =
315        clang::ObjCImplementationControl::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
390private:
391  typedef std::vector<std::string> TypeVector;
392
393  TypeVector m_type_vector;
394  bool m_is_valid = false;
395};
396
397bool 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_LOGF(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
525uint32_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_LOGF(log,
567                    "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext",
568                    result_iface_type.getAsString().data(), 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