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