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