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 mask: 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>(Val: 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(decl: 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(DC: decl_ctx, Name: name);
67 return false;
68 }
69
70 void CompleteType(clang::TagDecl *tag_decl) override {
71
72 Log *log(GetLog(
73 mask: 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 mask: 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(decl: 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 args: "AppleObjCDeclVendor AST",
137 args: 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(Val: 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: 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(x: 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<const 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(s: name_cursor, c: ':');
326 if (!colon_loc) {
327 selector_components.push_back(
328 x: &ast_ctx.Idents.get(Name: llvm::StringRef(name_cursor)));
329 break;
330 } else {
331 is_zero_argument = false;
332 selector_components.push_back(x: &ast_ctx.Idents.get(
333 Name: llvm::StringRef(name_cursor, colon_loc - name_cursor)));
334 name_cursor = colon_loc + 1;
335 }
336 }
337
338 const 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 NumArgs: is_zero_argument ? 0 : selector_components.size(),
345 IIV: identifier_infos);
346
347 clang::QualType ret_type =
348 ClangUtil::GetQualType(ct: type_realizer_sp->RealizeType(
349 ast_ctx&: clang_ast_ctxt, name: 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(ct: type_realizer_sp->RealizeType(
366 ast_ctx&: clang_ast_ctxt, name: 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(C&: ast_ctx,
378 Params: llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars),
379 SelLocs: 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(mask: 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(isa: 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(interface_decl: superclass_decl);
431 clang::ASTContext &context = m_ast_ctx->getASTContext();
432 interface_decl->setSuperClass(context.getTrivialTypeSourceInfo(
433 T: context.getObjCInterfaceType(Decl: 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 clang_ast_ctxt&: *m_ast_ctx, interface_decl, name, instance: true, type_realizer_sp: 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 clang_ast_ctxt&: *m_ast_ctx, interface_decl, name, instance: false, type_realizer_sp: 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 ast_ctx&: *m_ast_ctx, name: 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: name),
493 ClangUtil::GetQualType(ct: 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(mask: 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: name.GetStringRef());
548 clang::DeclarationName decl_name =
549 ast_ctx.DeclarationNames.getIdentifier(ID: &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>(Val: *lookup_result.begin())) {
557 if (log) {
558 clang::QualType result_iface_type =
559 ast_ctx.getObjCInterfaceType(Decl: 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(x: 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(Decl: 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(x: m_ast_ctx->GetCompilerDecl(iface_decl));
613 ret++;
614 break;
615 } while (false);
616
617 return ret;
618}
619

source code of lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp