18be30215SAlex Langford //===-- CxxModuleHandler.cpp ----------------------------------------------===// 28be30215SAlex Langford // 38be30215SAlex Langford // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48be30215SAlex Langford // See https://llvm.org/LICENSE.txt for license information. 58be30215SAlex Langford // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68be30215SAlex Langford // 78be30215SAlex Langford //===----------------------------------------------------------------------===// 88be30215SAlex Langford 98be30215SAlex Langford #include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" 108be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 118be30215SAlex Langford 128be30215SAlex Langford #include "lldb/Utility/Log.h" 138be30215SAlex Langford #include "clang/Sema/Lookup.h" 148be30215SAlex Langford #include "llvm/Support/Error.h" 158be30215SAlex Langford 168be30215SAlex Langford using namespace lldb_private; 178be30215SAlex Langford using namespace clang; 188be30215SAlex Langford 198be30215SAlex Langford CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) 208be30215SAlex Langford : m_importer(&importer), 218be30215SAlex Langford m_sema(TypeSystemClang::GetASTContext(target)->getSema()) { 228be30215SAlex Langford 238be30215SAlex Langford std::initializer_list<const char *> supported_names = { 248be30215SAlex Langford // containers 258be30215SAlex Langford "deque", 268be30215SAlex Langford "forward_list", 278be30215SAlex Langford "list", 288be30215SAlex Langford "queue", 298be30215SAlex Langford "stack", 308be30215SAlex Langford "vector", 318be30215SAlex Langford // pointers 328be30215SAlex Langford "shared_ptr", 338be30215SAlex Langford "unique_ptr", 348be30215SAlex Langford "weak_ptr", 358be30215SAlex Langford // utility 368be30215SAlex Langford "allocator", 37b8522252SRaphael Isemann "pair", 388be30215SAlex Langford }; 398be30215SAlex Langford m_supported_templates.insert(supported_names.begin(), supported_names.end()); 408be30215SAlex Langford } 418be30215SAlex Langford 428be30215SAlex Langford /// Builds a list of scopes that point into the given context. 438be30215SAlex Langford /// 448be30215SAlex Langford /// \param sema The sema that will be using the scopes. 458be30215SAlex Langford /// \param ctxt The context that the scope should look into. 468be30215SAlex Langford /// \param result A list of scopes. The scopes need to be freed by the caller 478be30215SAlex Langford /// (except the TUScope which is owned by the sema). 488be30215SAlex Langford static void makeScopes(Sema &sema, DeclContext *ctxt, 498be30215SAlex Langford std::vector<Scope *> &result) { 508be30215SAlex Langford // FIXME: The result should be a list of unique_ptrs, but the TUScope makes 518be30215SAlex Langford // this currently impossible as it's owned by the Sema. 528be30215SAlex Langford 538be30215SAlex Langford if (auto parent = ctxt->getParent()) { 548be30215SAlex Langford makeScopes(sema, parent, result); 558be30215SAlex Langford 568be30215SAlex Langford Scope *scope = 578be30215SAlex Langford new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics()); 588be30215SAlex Langford scope->setEntity(ctxt); 598be30215SAlex Langford result.push_back(scope); 608be30215SAlex Langford } else 618be30215SAlex Langford result.push_back(sema.TUScope); 628be30215SAlex Langford } 638be30215SAlex Langford 648be30215SAlex Langford /// Uses the Sema to look up the given name in the given DeclContext. 658be30215SAlex Langford static std::unique_ptr<LookupResult> 668be30215SAlex Langford emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) { 678be30215SAlex Langford IdentifierInfo &ident = sema.getASTContext().Idents.get(name); 688be30215SAlex Langford 698be30215SAlex Langford std::unique_ptr<LookupResult> lookup_result; 7006412daeSJonas Devlieghere lookup_result = std::make_unique<LookupResult>(sema, DeclarationName(&ident), 718be30215SAlex Langford SourceLocation(), 7206412daeSJonas Devlieghere Sema::LookupOrdinaryName); 738be30215SAlex Langford 748be30215SAlex Langford // Usually during parsing we already encountered the scopes we would use. But 758be30215SAlex Langford // here don't have these scopes so we have to emulate the behavior of the 768be30215SAlex Langford // Sema during parsing. 778be30215SAlex Langford std::vector<Scope *> scopes; 788be30215SAlex Langford makeScopes(sema, ctxt, scopes); 798be30215SAlex Langford 808be30215SAlex Langford // Now actually perform the lookup with the sema. 818be30215SAlex Langford sema.LookupName(*lookup_result, scopes.back()); 828be30215SAlex Langford 838be30215SAlex Langford // Delete all the allocated scopes beside the translation unit scope (which 848be30215SAlex Langford // has depth 0). 858be30215SAlex Langford for (Scope *s : scopes) 868be30215SAlex Langford if (s->getDepth() != 0) 878be30215SAlex Langford delete s; 888be30215SAlex Langford 898be30215SAlex Langford return lookup_result; 908be30215SAlex Langford } 918be30215SAlex Langford 928be30215SAlex Langford /// Error class for handling problems when finding a certain DeclContext. 938be30215SAlex Langford struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> { 948be30215SAlex Langford 958be30215SAlex Langford static char ID; 968be30215SAlex Langford 978be30215SAlex Langford MissingDeclContext(DeclContext *context, std::string error) 988be30215SAlex Langford : m_context(context), m_error(error) {} 998be30215SAlex Langford 1008be30215SAlex Langford DeclContext *m_context; 1018be30215SAlex Langford std::string m_error; 1028be30215SAlex Langford 1038be30215SAlex Langford void log(llvm::raw_ostream &OS) const override { 1048be30215SAlex Langford OS << llvm::formatv("error when reconstructing context of kind {0}:{1}", 1058be30215SAlex Langford m_context->getDeclKindName(), m_error); 1068be30215SAlex Langford } 1078be30215SAlex Langford 1088be30215SAlex Langford std::error_code convertToErrorCode() const override { 1098be30215SAlex Langford return llvm::inconvertibleErrorCode(); 1108be30215SAlex Langford } 1118be30215SAlex Langford }; 1128be30215SAlex Langford 1138be30215SAlex Langford char MissingDeclContext::ID = 0; 1148be30215SAlex Langford 1158be30215SAlex Langford /// Given a foreign decl context, this function finds the equivalent local 1168be30215SAlex Langford /// decl context in the ASTContext of the given Sema. Potentially deserializes 1178be30215SAlex Langford /// decls from the 'std' module if necessary. 1188be30215SAlex Langford static llvm::Expected<DeclContext *> 1198be30215SAlex Langford getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) { 1208be30215SAlex Langford 1218be30215SAlex Langford // Inline namespaces don't matter for lookups, so let's skip them. 1228be30215SAlex Langford while (foreign_ctxt && foreign_ctxt->isInlineNamespace()) 1238be30215SAlex Langford foreign_ctxt = foreign_ctxt->getParent(); 1248be30215SAlex Langford 1258be30215SAlex Langford // If the foreign context is the TU, we just return the local TU. 1268be30215SAlex Langford if (foreign_ctxt->isTranslationUnit()) 1278be30215SAlex Langford return sema.getASTContext().getTranslationUnitDecl(); 1288be30215SAlex Langford 1298be30215SAlex Langford // Recursively find/build the parent DeclContext. 1308be30215SAlex Langford llvm::Expected<DeclContext *> parent = 1318be30215SAlex Langford getEqualLocalDeclContext(sema, foreign_ctxt->getParent()); 1328be30215SAlex Langford if (!parent) 1338be30215SAlex Langford return parent; 1348be30215SAlex Langford 1358be30215SAlex Langford // We currently only support building namespaces. 1368be30215SAlex Langford if (foreign_ctxt->isNamespace()) { 1378be30215SAlex Langford NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt); 1388be30215SAlex Langford llvm::StringRef ns_name = ns->getName(); 1398be30215SAlex Langford 1408be30215SAlex Langford auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent); 1418be30215SAlex Langford for (NamedDecl *named_decl : *lookup_result) { 1428be30215SAlex Langford if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl)) 1438be30215SAlex Langford return DC->getPrimaryContext(); 1448be30215SAlex Langford } 1458be30215SAlex Langford return llvm::make_error<MissingDeclContext>( 1468be30215SAlex Langford foreign_ctxt, 1478be30215SAlex Langford "Couldn't find namespace " + ns->getQualifiedNameAsString()); 1488be30215SAlex Langford } 1498be30215SAlex Langford 1508be30215SAlex Langford return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context "); 1518be30215SAlex Langford } 1528be30215SAlex Langford 1538be30215SAlex Langford /// Returns true iff tryInstantiateStdTemplate supports instantiating a template 1548be30215SAlex Langford /// with the given template arguments. 1558be30215SAlex Langford static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) { 1568be30215SAlex Langford for (const TemplateArgument &arg : a) { 1578be30215SAlex Langford switch (arg.getKind()) { 1588be30215SAlex Langford case TemplateArgument::Type: 1598be30215SAlex Langford case TemplateArgument::Integral: 1608be30215SAlex Langford break; 1618be30215SAlex Langford default: 1628be30215SAlex Langford // TemplateArgument kind hasn't been handled yet. 1638be30215SAlex Langford return false; 1648be30215SAlex Langford } 1658be30215SAlex Langford } 1668be30215SAlex Langford return true; 1678be30215SAlex Langford } 1688be30215SAlex Langford 1698be30215SAlex Langford /// Constructor function for Clang declarations. Ensures that the created 1708be30215SAlex Langford /// declaration is registered with the ASTImporter. 1718be30215SAlex Langford template <typename T, typename... Args> 1728be30215SAlex Langford T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) { 1738be30215SAlex Langford T *to_d = T::Create(std::forward<Args>(args)...); 1748be30215SAlex Langford importer.RegisterImportedDecl(from_d, to_d); 1758be30215SAlex Langford return to_d; 1768be30215SAlex Langford } 1778be30215SAlex Langford 1788be30215SAlex Langford llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { 1798be30215SAlex Langford Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); 1808be30215SAlex Langford 1818be30215SAlex Langford // If we don't have a template to instiantiate, then there is nothing to do. 1828be30215SAlex Langford auto td = dyn_cast<ClassTemplateSpecializationDecl>(d); 1838be30215SAlex Langford if (!td) 184*0b44bb8dSRaphael Isemann return llvm::None; 1858be30215SAlex Langford 1868be30215SAlex Langford // We only care about templates in the std namespace. 1878be30215SAlex Langford if (!td->getDeclContext()->isStdNamespace()) 188*0b44bb8dSRaphael Isemann return llvm::None; 1898be30215SAlex Langford 190efb328f6SEric Christopher // We have a list of supported template names. 191*0b44bb8dSRaphael Isemann if (!m_supported_templates.contains(td->getName())) 192*0b44bb8dSRaphael Isemann return llvm::None; 1938be30215SAlex Langford 1948be30215SAlex Langford // Early check if we even support instantiating this template. We do this 1958be30215SAlex Langford // before we import anything into the target AST. 1968be30215SAlex Langford auto &foreign_args = td->getTemplateInstantiationArgs(); 1978be30215SAlex Langford if (!templateArgsAreSupported(foreign_args.asArray())) 198*0b44bb8dSRaphael Isemann return llvm::None; 1998be30215SAlex Langford 2008be30215SAlex Langford // Find the local DeclContext that corresponds to the DeclContext of our 2018be30215SAlex Langford // decl we want to import. 2028be30215SAlex Langford llvm::Expected<DeclContext *> to_context = 2038be30215SAlex Langford getEqualLocalDeclContext(*m_sema, td->getDeclContext()); 2048be30215SAlex Langford if (!to_context) { 2058be30215SAlex Langford LLDB_LOG_ERROR(log, to_context.takeError(), 2068be30215SAlex Langford "Got error while searching equal local DeclContext for decl " 2078be30215SAlex Langford "'{1}':\n{0}", 2088be30215SAlex Langford td->getName()); 209*0b44bb8dSRaphael Isemann return llvm::None; 2108be30215SAlex Langford } 2118be30215SAlex Langford 2128be30215SAlex Langford // Look up the template in our local context. 2138be30215SAlex Langford std::unique_ptr<LookupResult> lookup = 2148be30215SAlex Langford emulateLookupInCtxt(*m_sema, td->getName(), *to_context); 2158be30215SAlex Langford 2168be30215SAlex Langford ClassTemplateDecl *new_class_template = nullptr; 2178be30215SAlex Langford for (auto LD : *lookup) { 2188be30215SAlex Langford if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD))) 2198be30215SAlex Langford break; 2208be30215SAlex Langford } 2218be30215SAlex Langford if (!new_class_template) 222*0b44bb8dSRaphael Isemann return llvm::None; 2238be30215SAlex Langford 2248be30215SAlex Langford // Import the foreign template arguments. 2258be30215SAlex Langford llvm::SmallVector<TemplateArgument, 4> imported_args; 2268be30215SAlex Langford 2278be30215SAlex Langford // If this logic is changed, also update templateArgsAreSupported. 2288be30215SAlex Langford for (const TemplateArgument &arg : foreign_args.asArray()) { 2298be30215SAlex Langford switch (arg.getKind()) { 2308be30215SAlex Langford case TemplateArgument::Type: { 2318be30215SAlex Langford llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); 2328be30215SAlex Langford if (!type) { 2338be30215SAlex Langford LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); 234*0b44bb8dSRaphael Isemann return llvm::None; 2358be30215SAlex Langford } 2368be30215SAlex Langford imported_args.push_back(TemplateArgument(*type)); 2378be30215SAlex Langford break; 2388be30215SAlex Langford } 2398be30215SAlex Langford case TemplateArgument::Integral: { 2408be30215SAlex Langford llvm::APSInt integral = arg.getAsIntegral(); 2418be30215SAlex Langford llvm::Expected<QualType> type = 2428be30215SAlex Langford m_importer->Import(arg.getIntegralType()); 2438be30215SAlex Langford if (!type) { 2448be30215SAlex Langford LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); 245*0b44bb8dSRaphael Isemann return llvm::None; 2468be30215SAlex Langford } 2478be30215SAlex Langford imported_args.push_back( 2488be30215SAlex Langford TemplateArgument(d->getASTContext(), integral, *type)); 2498be30215SAlex Langford break; 2508be30215SAlex Langford } 2518be30215SAlex Langford default: 2528be30215SAlex Langford assert(false && "templateArgsAreSupported not updated?"); 2538be30215SAlex Langford } 2548be30215SAlex Langford } 2558be30215SAlex Langford 2568be30215SAlex Langford // Find the class template specialization declaration that 2578be30215SAlex Langford // corresponds to these arguments. 2588be30215SAlex Langford void *InsertPos = nullptr; 2598be30215SAlex Langford ClassTemplateSpecializationDecl *result = 2608be30215SAlex Langford new_class_template->findSpecialization(imported_args, InsertPos); 2618be30215SAlex Langford 2628be30215SAlex Langford if (result) { 2638be30215SAlex Langford // We found an existing specialization in the module that fits our arguments 2648be30215SAlex Langford // so we can treat it as the result and register it with the ASTImporter. 2658be30215SAlex Langford m_importer->RegisterImportedDecl(d, result); 2668be30215SAlex Langford return result; 2678be30215SAlex Langford } 2688be30215SAlex Langford 2698be30215SAlex Langford // Instantiate the template. 2708be30215SAlex Langford result = createDecl<ClassTemplateSpecializationDecl>( 2718be30215SAlex Langford *m_importer, d, m_sema->getASTContext(), 2728be30215SAlex Langford new_class_template->getTemplatedDecl()->getTagKind(), 2738be30215SAlex Langford new_class_template->getDeclContext(), 2748be30215SAlex Langford new_class_template->getTemplatedDecl()->getLocation(), 2758be30215SAlex Langford new_class_template->getLocation(), new_class_template, imported_args, 2768be30215SAlex Langford nullptr); 2778be30215SAlex Langford 2788be30215SAlex Langford new_class_template->AddSpecialization(result, InsertPos); 2798be30215SAlex Langford if (new_class_template->isOutOfLine()) 2808be30215SAlex Langford result->setLexicalDeclContext( 2818be30215SAlex Langford new_class_template->getLexicalDeclContext()); 2828be30215SAlex Langford return result; 2838be30215SAlex Langford } 2848be30215SAlex Langford 2858be30215SAlex Langford llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) { 2868be30215SAlex Langford if (!isValid()) 2878be30215SAlex Langford return {}; 2888be30215SAlex Langford 2898be30215SAlex Langford return tryInstantiateStdTemplate(d); 2908be30215SAlex Langford } 291