1//===-- AppleObjCSymbolVendor.cpp -------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "AppleObjCTypeVendor.h"
11
12#include "lldb/Core/Log.h"
13#include "lldb/Core/Module.h"
14#include "lldb/Expression/ASTDumper.h"
15#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
16#include "lldb/Target/ObjCLanguageRuntime.h"
17#include "lldb/Target/Process.h"
18#include "lldb/Target/Target.h"
19
20#include "clang/AST/ASTContext.h"
21#include "clang/AST/DeclObjC.h"
22
23using namespace lldb_private;
24
25class lldb_private::AppleObjCExternalASTSource : public ClangExternalASTSourceCommon
26{
27public:
28    AppleObjCExternalASTSource (AppleObjCTypeVendor &type_vendor) :
29        m_type_vendor(type_vendor)
30    {
31    }
32
33    bool
34    FindExternalVisibleDeclsByName (const clang::DeclContext *decl_ctx,
35                                    clang::DeclarationName name)
36    {
37        static unsigned int invocation_id = 0;
38        unsigned int current_id = invocation_id++;
39
40        Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
41
42        if (log)
43        {
44            log->Printf("AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
45                        current_id,
46                        &decl_ctx->getParentASTContext(),
47                        name.getAsString().c_str(),
48                        decl_ctx->getDeclKindName(),
49                        decl_ctx);
50        }
51
52        do
53        {
54            const clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
55
56            if (!interface_decl)
57                break;
58
59            clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl);
60
61            if (!m_type_vendor.FinishDecl(non_const_interface_decl))
62                break;
63
64            clang::DeclContext::lookup_const_result result = non_const_interface_decl->lookup(name);
65
66            return (result.size() != 0);
67        }
68        while(0);
69
70        SetNoExternalVisibleDeclsForName(decl_ctx, name);
71        return false;
72    }
73
74    clang::ExternalLoadResult
75    FindExternalLexicalDecls (const clang::DeclContext *DC,
76                              bool (*isKindWeWant)(clang::Decl::Kind),
77                              llvm::SmallVectorImpl<clang::Decl*> &Decls)
78    {
79        return clang::ELR_Success;
80    }
81
82    void
83    CompleteType (clang::TagDecl *tag_decl)
84    {
85        static unsigned int invocation_id = 0;
86        unsigned int current_id = invocation_id++;
87
88        Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
89
90        if (log)
91        {
92            log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
93                        current_id,
94                        &tag_decl->getASTContext(),
95                        tag_decl,
96                        tag_decl->getName().str().c_str());
97
98            log->Printf("  AOEAS::CT[%u] Before:", current_id);
99            ASTDumper dumper((clang::Decl*)tag_decl);
100            dumper.ToLog(log, "    [CT] ");
101        }
102
103        if (log)
104        {
105            log->Printf("  AOEAS::CT[%u] After:", current_id);
106            ASTDumper dumper((clang::Decl*)tag_decl);
107            dumper.ToLog(log, "    [CT] ");
108        }
109        return;
110    }
111
112    void
113    CompleteType (clang::ObjCInterfaceDecl *interface_decl)
114    {
115        static unsigned int invocation_id = 0;
116        unsigned int current_id = invocation_id++;
117
118        Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
119
120        if (log)
121        {
122            log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
123                        current_id,
124                        &interface_decl->getASTContext(),
125                        interface_decl,
126                        interface_decl->getName().str().c_str());
127
128            log->Printf("  AOEAS::CT[%u] Before:", current_id);
129            ASTDumper dumper((clang::Decl*)interface_decl);
130            dumper.ToLog(log, "    [CT] ");
131        }
132
133        m_type_vendor.FinishDecl(interface_decl);
134
135        if (log)
136        {
137            log->Printf("  [CT] After:");
138            ASTDumper dumper((clang::Decl*)interface_decl);
139            dumper.ToLog(log, "    [CT] ");
140        }
141        return;
142    }
143
144    bool
145    layoutRecordType(const clang::RecordDecl *Record,
146                     uint64_t &Size,
147                     uint64_t &Alignment,
148                     llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
149                     llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
150                     llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
151    {
152        return false;
153    }
154
155    void StartTranslationUnit (clang::ASTConsumer *Consumer)
156    {
157        clang::TranslationUnitDecl *translation_unit_decl = m_type_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl();
158        translation_unit_decl->setHasExternalVisibleStorage();
159        translation_unit_decl->setHasExternalLexicalStorage();
160    }
161private:
162    AppleObjCTypeVendor                                    &m_type_vendor;
163};
164
165AppleObjCTypeVendor::AppleObjCTypeVendor(ObjCLanguageRuntime &runtime) :
166    TypeVendor(),
167    m_runtime(runtime),
168    m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str())
169{
170    m_external_source = new AppleObjCExternalASTSource (*this);
171    llvm::OwningPtr<clang::ExternalASTSource> external_source_owning_ptr (m_external_source);
172    m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr);
173}
174
175clang::ObjCInterfaceDecl*
176AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
177{
178    ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
179
180    if (iter != m_isa_to_interface.end())
181        return iter->second;
182
183    clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
184
185    ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(isa);
186
187    if (!descriptor)
188        return NULL;
189
190    const ConstString &name(descriptor->GetClassName());
191
192    clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
193
194    clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
195                                                                                ast_ctx->getTranslationUnitDecl(),
196                                                                                clang::SourceLocation(),
197                                                                                &identifier_info,
198                                                                                NULL);
199
200    ClangASTMetadata meta_data;
201    meta_data.SetISAPtr(isa);
202    m_external_source->SetMetadata(new_iface_decl, meta_data);
203
204    new_iface_decl->setHasExternalVisibleStorage();
205    new_iface_decl->setHasExternalLexicalStorage();
206
207    ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
208
209    m_isa_to_interface[isa] = new_iface_decl;
210
211    return new_iface_decl;
212}
213
214class ObjCRuntimeMethodType
215{
216public:
217    ObjCRuntimeMethodType (const char *types) : m_is_valid(false)
218    {
219        const char *cursor = types;
220        enum ParserState {
221            Start = 0,
222            InType,
223            InPos
224        } state = Start;
225        const char *type = NULL;
226        int brace_depth = 0;
227
228        uint32_t stepsLeft = 256;
229
230        while (1)
231        {
232            if (--stepsLeft == 0)
233            {
234                m_is_valid = false;
235                return;
236            }
237
238            switch (state)
239            {
240            case Start:
241                {
242                    switch (*cursor)
243                    {
244                    default:
245                        state = InType;
246                        type = cursor;
247                        break;
248                    case '\0':
249                        m_is_valid = true;
250                        return;
251                    case '0': case '1': case '2': case '3': case '4':
252                    case '5': case '6': case '7': case '8': case '9':
253                        m_is_valid = false;
254                        return;
255                    }
256                }
257                break;
258            case InType:
259                {
260                    switch (*cursor)
261                    {
262                    default:
263                        ++cursor;
264                        break;
265                    case '0': case '1': case '2': case '3': case '4':
266                    case '5': case '6': case '7': case '8': case '9':
267                        if (!brace_depth)
268                        {
269                            state = InPos;
270                            if (type)
271                            {
272                                m_type_vector.push_back(std::string(type, (cursor - type)));
273                            }
274                            else
275                            {
276                                m_is_valid = false;
277                                return;
278                            }
279                            type = NULL;
280                        }
281                        else
282                        {
283                            ++cursor;
284                        }
285                        break;
286                    case '[': case '{': case '(':
287                        ++brace_depth;
288                        ++cursor;
289                        break;
290                    case ']': case '}': case ')':
291                        if (!brace_depth)
292                        {
293                            m_is_valid = false;
294                            return;
295                        }
296                        --brace_depth;
297                        ++cursor;
298                        break;
299                    case '\0':
300                        m_is_valid = false;
301                        return;
302                    }
303                }
304                break;
305            case InPos:
306                {
307                    switch (*cursor)
308                    {
309                    default:
310                        state = InType;
311                        type = cursor;
312                        break;
313                    case '0': case '1': case '2': case '3': case '4':
314                    case '5': case '6': case '7': case '8': case '9':
315                        ++cursor;
316                        break;
317                    case '\0':
318                        m_is_valid = true;
319                        return;
320                    }
321                }
322                break;
323            }
324        }
325    }
326
327    clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance)
328    {
329        if (!m_is_valid || m_type_vector.size() < 3)
330            return NULL;
331
332        clang::ASTContext &ast_ctx(interface_decl->getASTContext());
333
334        clang::QualType return_qual_type;
335
336        const bool isInstance = instance;
337        const bool isVariadic = false;
338        const bool isSynthesized = false;
339        const bool isImplicitlyDeclared = true;
340        const bool isDefined = false;
341        const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None;
342        const bool HasRelatedResultType = false;
343
344        std::vector <clang::IdentifierInfo *> selector_components;
345
346        const char *name_cursor = name;
347        bool is_zero_argument = true;
348
349        while (*name_cursor != '\0')
350        {
351            const char *colon_loc = strchr(name_cursor, ':');
352            if (!colon_loc)
353            {
354                selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
355                break;
356            }
357            else
358            {
359                is_zero_argument = false;
360                selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor, colon_loc - name_cursor)));
361                name_cursor = colon_loc + 1;
362            }
363        }
364
365        clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data());
366
367        clang::QualType ret_type = BuildType(ast_ctx, m_type_vector[0].c_str());
368
369        if (ret_type.isNull())
370            return NULL;
371
372        clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(ast_ctx,
373                                                                   clang::SourceLocation(),
374                                                                   clang::SourceLocation(),
375                                                                   sel,
376                                                                   ret_type,
377                                                                   NULL,
378                                                                   interface_decl,
379                                                                   isInstance,
380                                                                   isVariadic,
381                                                                   isSynthesized,
382                                                                   isImplicitlyDeclared,
383                                                                   isDefined,
384                                                                   impControl,
385                                                                   HasRelatedResultType);
386
387        std::vector <clang::ParmVarDecl*> parm_vars;
388
389        for (size_t ai = 3, ae = m_type_vector.size();
390             ai != ae;
391             ++ai)
392        {
393            clang::QualType arg_type = BuildType(ast_ctx, m_type_vector[ai].c_str());
394
395            if (arg_type.isNull())
396                return NULL; // well, we just wasted a bunch of time.  Wish we could delete the stuff we'd just made!
397
398            parm_vars.push_back(clang::ParmVarDecl::Create(ast_ctx,
399                                                           ret,
400                                                           clang::SourceLocation(),
401                                                           clang::SourceLocation(),
402                                                           NULL,
403                                                           arg_type,
404                                                           NULL,
405                                                           clang::SC_None,
406                                                           NULL));
407        }
408
409        ret->setMethodParams(ast_ctx, llvm::ArrayRef<clang::ParmVarDecl*>(parm_vars), llvm::ArrayRef<clang::SourceLocation>());
410
411        return ret;
412    }
413private:
414    clang::QualType BuildType (clang::ASTContext &ast_ctx, const char *type)
415    {
416        if (!type)
417            return clang::QualType();
418
419        switch (*type)
420        {
421        default:
422            return ast_ctx.UnknownAnyTy;
423        case 'r':
424            {
425                clang::QualType target_type = BuildType(ast_ctx, type+1);
426                if (target_type.isNull())
427                    return clang::QualType();
428                else if (target_type == ast_ctx.UnknownAnyTy)
429                    return ast_ctx.UnknownAnyTy;
430                else
431                    return ast_ctx.getConstType(target_type);
432            }
433        case '^':
434        {
435            clang::QualType target_type = BuildType(ast_ctx, type+1);
436            if (target_type.isNull())
437                return clang::QualType();
438            else if (target_type == ast_ctx.UnknownAnyTy)
439                return ast_ctx.UnknownAnyTy;
440            else
441                return ast_ctx.getPointerType(target_type);
442        }
443        case 'c':
444            return ast_ctx.CharTy;
445        case 'i':
446            return ast_ctx.IntTy;
447        case 's':
448            return ast_ctx.ShortTy;
449        case 'l':
450            if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
451                return ast_ctx.IntTy;
452            else
453                return ast_ctx.LongTy;
454        case 'q':
455            return ast_ctx.LongLongTy;
456        case 'C':
457            return ast_ctx.UnsignedCharTy;
458        case 'I':
459            return ast_ctx.UnsignedIntTy;
460        case 'S':
461            return ast_ctx.UnsignedShortTy;
462        case 'L':
463            if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
464                return ast_ctx.UnsignedIntTy;
465            else
466                return ast_ctx.UnsignedLongTy;
467        case 'Q':
468            return ast_ctx.UnsignedLongLongTy;
469        case 'f':
470            return ast_ctx.FloatTy;
471        case 'd':
472            return ast_ctx.DoubleTy;
473        case 'B':
474            return ast_ctx.BoolTy;
475        case 'v':
476            return ast_ctx.VoidTy;
477        case '*':
478            return ast_ctx.getPointerType(ast_ctx.CharTy);
479        case '@':
480            return ast_ctx.getObjCIdType();
481        case '#':
482            return ast_ctx.getObjCClassType();
483        case ':':
484            return ast_ctx.getObjCSelType();
485        }
486        return clang::QualType();
487    }
488
489    typedef std::vector <std::string> TypeVector;
490
491    TypeVector  m_type_vector;
492    bool        m_is_valid;
493};
494
495bool
496AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
497{
498    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
499
500    ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl);
501    ObjCLanguageRuntime::ObjCISA objc_isa = 0;
502    if (metadata)
503     objc_isa = metadata->GetISAPtr();
504
505    if (!objc_isa)
506        return false;
507
508    if (!interface_decl->hasExternalVisibleStorage())
509        return true;
510
511    interface_decl->startDefinition();
512
513    interface_decl->setHasExternalVisibleStorage(false);
514    interface_decl->setHasExternalLexicalStorage(false);
515
516    ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(objc_isa);
517
518    if (!descriptor)
519        return false;
520
521    auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa)
522    {
523        clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
524        if (!superclass_decl)
525            return;
526        interface_decl->setSuperClass(superclass_decl);
527    };
528
529    auto instance_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool
530    {
531        ObjCRuntimeMethodType method_type(types);
532
533        clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true);
534
535        if (log)
536            log->Printf("[  AOTV::FD] Instance method [%s] [%s]", name, types);
537
538        if (method_decl)
539            interface_decl->addDecl(method_decl);
540
541        return false;
542    };
543
544    auto class_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool
545    {
546        ObjCRuntimeMethodType method_type(types);
547
548        clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false);
549
550        if (log)
551            log->Printf("[  AOTV::FD] Class method [%s] [%s]", name, types);
552
553        if (method_decl)
554            interface_decl->addDecl(method_decl);
555
556        return false;
557    };
558
559    if (log)
560    {
561        ASTDumper method_dumper ((clang::Decl*)interface_decl);
562
563        log->Printf("[AppleObjCTypeVendor::FinishDecl] Finishing Objective-C interface for %s", descriptor->GetClassName().AsCString());
564    }
565
566
567    if (!descriptor->Describe(superclass_func,
568                              instance_method_func,
569                              class_method_func,
570                              std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr)))
571        return false;
572
573    if (log)
574    {
575        ASTDumper method_dumper ((clang::Decl*)interface_decl);
576
577        log->Printf("[AppleObjCTypeVendor::FinishDecl] Finished Objective-C interface");
578
579        method_dumper.ToLog(log, "  [AOTV::FD] ");
580    }
581
582    return true;
583}
584
585uint32_t
586AppleObjCTypeVendor::FindTypes (const ConstString &name,
587                                bool append,
588                                uint32_t max_matches,
589                                std::vector <ClangASTType> &types)
590{
591    static unsigned int invocation_id = 0;
592    unsigned int current_id = invocation_id++;
593
594    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));  // FIXME - a more appropriate log channel?
595
596    if (log)
597        log->Printf("AppleObjCTypeVendor::FindTypes [%u] ('%s', %s, %u, )",
598                    current_id,
599                    (const char*)name.AsCString(),
600                    append ? "true" : "false",
601                    max_matches);
602
603    if (!append)
604        types.clear();
605
606    uint32_t ret = 0;
607
608    do
609    {
610        // See if the type is already in our ASTContext.
611
612        clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
613
614        clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
615        clang::DeclarationName decl_name = ast_ctx->DeclarationNames.getIdentifier(&identifier_info);
616
617        clang::DeclContext::lookup_const_result lookup_result = ast_ctx->getTranslationUnitDecl()->lookup(decl_name);
618
619        if (!lookup_result.empty())
620        {
621            if (const clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0]))
622            {
623                clang::QualType result_iface_type = ast_ctx->getObjCInterfaceType(result_iface_decl);
624
625                if (log)
626                {
627                    ASTDumper dumper(result_iface_type);
628
629                    uint64_t isa_value = LLDB_INVALID_ADDRESS;
630                    ClangASTMetadata *metadata = m_external_source->GetMetadata(result_iface_decl);
631                    if (metadata)
632                        isa_value = metadata->GetISAPtr();
633
634                    log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 ") in the ASTContext",
635                                current_id,
636                                dumper.GetCString(),
637                                isa_value);
638                }
639
640                types.push_back(ClangASTType(ast_ctx, result_iface_type.getAsOpaquePtr()));
641                ret++;
642                break;
643            }
644            else
645            {
646                if (log)
647                    log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but it's not something we know about",
648                                current_id);
649                break;
650            }
651        }
652        else if(log)
653        {
654            log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext",
655                        current_id,
656                        name.AsCString());
657        }
658
659        // It's not.  If it exists, we have to put it into our ASTContext.
660
661        ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
662
663        if (!isa)
664        {
665            if (log)
666                log->Printf("AOCTV::FT [%u] Couldn't find the isa",
667                            current_id);
668
669            break;
670        }
671
672        clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
673
674        if (!iface_decl)
675        {
676            if (log)
677                log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%" PRIx64,
678                            current_id,
679                            (uint64_t)isa);
680
681            break;
682        }
683
684        clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl);
685
686        if (log)
687        {
688            ASTDumper dumper(new_iface_type);
689            log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")",
690                        current_id,
691                        dumper.GetCString(),
692                        (uint64_t)isa);
693        }
694
695        types.push_back(ClangASTType(ast_ctx, new_iface_type.getAsOpaquePtr()));
696        ret++;
697        break;
698    } while (0);
699
700    return ret;
701}
702