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