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