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