1cfca06d7SDimitry Andric //===-- CxxModuleHandler.cpp ----------------------------------------------===//
25f29bb8aSDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f29bb8aSDimitry Andric //
75f29bb8aSDimitry Andric //===----------------------------------------------------------------------===//
85f29bb8aSDimitry Andric
9cfca06d7SDimitry Andric #include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
10cfca06d7SDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
115f29bb8aSDimitry Andric
12145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
135f29bb8aSDimitry Andric #include "lldb/Utility/Log.h"
145f29bb8aSDimitry Andric #include "clang/Sema/Lookup.h"
155f29bb8aSDimitry Andric #include "llvm/Support/Error.h"
16e3b55780SDimitry Andric #include <optional>
175f29bb8aSDimitry Andric
185f29bb8aSDimitry Andric using namespace lldb_private;
195f29bb8aSDimitry Andric using namespace clang;
205f29bb8aSDimitry Andric
CxxModuleHandler(ASTImporter & importer,ASTContext * target)215f29bb8aSDimitry Andric CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target)
225f29bb8aSDimitry Andric : m_importer(&importer),
23cfca06d7SDimitry Andric m_sema(TypeSystemClang::GetASTContext(target)->getSema()) {
245f29bb8aSDimitry Andric
255f29bb8aSDimitry Andric std::initializer_list<const char *> supported_names = {
265f29bb8aSDimitry Andric // containers
27b60736ecSDimitry Andric "array",
285f29bb8aSDimitry Andric "deque",
295f29bb8aSDimitry Andric "forward_list",
305f29bb8aSDimitry Andric "list",
315f29bb8aSDimitry Andric "queue",
325f29bb8aSDimitry Andric "stack",
335f29bb8aSDimitry Andric "vector",
345f29bb8aSDimitry Andric // pointers
355f29bb8aSDimitry Andric "shared_ptr",
365f29bb8aSDimitry Andric "unique_ptr",
375f29bb8aSDimitry Andric "weak_ptr",
38344a3780SDimitry Andric // iterator
39344a3780SDimitry Andric "move_iterator",
40344a3780SDimitry Andric "__wrap_iter",
415f29bb8aSDimitry Andric // utility
425f29bb8aSDimitry Andric "allocator",
43b60736ecSDimitry Andric "pair",
445f29bb8aSDimitry Andric };
455f29bb8aSDimitry Andric m_supported_templates.insert(supported_names.begin(), supported_names.end());
465f29bb8aSDimitry Andric }
475f29bb8aSDimitry Andric
485f29bb8aSDimitry Andric /// Builds a list of scopes that point into the given context.
495f29bb8aSDimitry Andric ///
505f29bb8aSDimitry Andric /// \param sema The sema that will be using the scopes.
515f29bb8aSDimitry Andric /// \param ctxt The context that the scope should look into.
525f29bb8aSDimitry Andric /// \param result A list of scopes. The scopes need to be freed by the caller
535f29bb8aSDimitry Andric /// (except the TUScope which is owned by the sema).
makeScopes(Sema & sema,DeclContext * ctxt,std::vector<Scope * > & result)545f29bb8aSDimitry Andric static void makeScopes(Sema &sema, DeclContext *ctxt,
555f29bb8aSDimitry Andric std::vector<Scope *> &result) {
565f29bb8aSDimitry Andric // FIXME: The result should be a list of unique_ptrs, but the TUScope makes
575f29bb8aSDimitry Andric // this currently impossible as it's owned by the Sema.
585f29bb8aSDimitry Andric
595f29bb8aSDimitry Andric if (auto parent = ctxt->getParent()) {
605f29bb8aSDimitry Andric makeScopes(sema, parent, result);
615f29bb8aSDimitry Andric
625f29bb8aSDimitry Andric Scope *scope =
635f29bb8aSDimitry Andric new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics());
645f29bb8aSDimitry Andric scope->setEntity(ctxt);
655f29bb8aSDimitry Andric result.push_back(scope);
665f29bb8aSDimitry Andric } else
675f29bb8aSDimitry Andric result.push_back(sema.TUScope);
685f29bb8aSDimitry Andric }
695f29bb8aSDimitry Andric
705f29bb8aSDimitry Andric /// Uses the Sema to look up the given name in the given DeclContext.
715f29bb8aSDimitry Andric static std::unique_ptr<LookupResult>
emulateLookupInCtxt(Sema & sema,llvm::StringRef name,DeclContext * ctxt)725f29bb8aSDimitry Andric emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) {
735f29bb8aSDimitry Andric IdentifierInfo &ident = sema.getASTContext().Idents.get(name);
745f29bb8aSDimitry Andric
755f29bb8aSDimitry Andric std::unique_ptr<LookupResult> lookup_result;
76cfca06d7SDimitry Andric lookup_result = std::make_unique<LookupResult>(sema, DeclarationName(&ident),
775f29bb8aSDimitry Andric SourceLocation(),
78cfca06d7SDimitry Andric Sema::LookupOrdinaryName);
795f29bb8aSDimitry Andric
805f29bb8aSDimitry Andric // Usually during parsing we already encountered the scopes we would use. But
815f29bb8aSDimitry Andric // here don't have these scopes so we have to emulate the behavior of the
825f29bb8aSDimitry Andric // Sema during parsing.
835f29bb8aSDimitry Andric std::vector<Scope *> scopes;
845f29bb8aSDimitry Andric makeScopes(sema, ctxt, scopes);
855f29bb8aSDimitry Andric
865f29bb8aSDimitry Andric // Now actually perform the lookup with the sema.
875f29bb8aSDimitry Andric sema.LookupName(*lookup_result, scopes.back());
885f29bb8aSDimitry Andric
895f29bb8aSDimitry Andric // Delete all the allocated scopes beside the translation unit scope (which
905f29bb8aSDimitry Andric // has depth 0).
915f29bb8aSDimitry Andric for (Scope *s : scopes)
925f29bb8aSDimitry Andric if (s->getDepth() != 0)
935f29bb8aSDimitry Andric delete s;
945f29bb8aSDimitry Andric
955f29bb8aSDimitry Andric return lookup_result;
965f29bb8aSDimitry Andric }
975f29bb8aSDimitry Andric
985f29bb8aSDimitry Andric /// Error class for handling problems when finding a certain DeclContext.
995f29bb8aSDimitry Andric struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
1005f29bb8aSDimitry Andric
1015f29bb8aSDimitry Andric static char ID;
1025f29bb8aSDimitry Andric
MissingDeclContextMissingDeclContext1035f29bb8aSDimitry Andric MissingDeclContext(DeclContext *context, std::string error)
1045f29bb8aSDimitry Andric : m_context(context), m_error(error) {}
1055f29bb8aSDimitry Andric
1065f29bb8aSDimitry Andric DeclContext *m_context;
1075f29bb8aSDimitry Andric std::string m_error;
1085f29bb8aSDimitry Andric
logMissingDeclContext1095f29bb8aSDimitry Andric void log(llvm::raw_ostream &OS) const override {
1105f29bb8aSDimitry Andric OS << llvm::formatv("error when reconstructing context of kind {0}:{1}",
1115f29bb8aSDimitry Andric m_context->getDeclKindName(), m_error);
1125f29bb8aSDimitry Andric }
1135f29bb8aSDimitry Andric
convertToErrorCodeMissingDeclContext1145f29bb8aSDimitry Andric std::error_code convertToErrorCode() const override {
1155f29bb8aSDimitry Andric return llvm::inconvertibleErrorCode();
1165f29bb8aSDimitry Andric }
1175f29bb8aSDimitry Andric };
1185f29bb8aSDimitry Andric
1195f29bb8aSDimitry Andric char MissingDeclContext::ID = 0;
1205f29bb8aSDimitry Andric
1215f29bb8aSDimitry Andric /// Given a foreign decl context, this function finds the equivalent local
1225f29bb8aSDimitry Andric /// decl context in the ASTContext of the given Sema. Potentially deserializes
1235f29bb8aSDimitry Andric /// decls from the 'std' module if necessary.
1245f29bb8aSDimitry Andric static llvm::Expected<DeclContext *>
getEqualLocalDeclContext(Sema & sema,DeclContext * foreign_ctxt)1255f29bb8aSDimitry Andric getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
1265f29bb8aSDimitry Andric
1275f29bb8aSDimitry Andric // Inline namespaces don't matter for lookups, so let's skip them.
1285f29bb8aSDimitry Andric while (foreign_ctxt && foreign_ctxt->isInlineNamespace())
1295f29bb8aSDimitry Andric foreign_ctxt = foreign_ctxt->getParent();
1305f29bb8aSDimitry Andric
1315f29bb8aSDimitry Andric // If the foreign context is the TU, we just return the local TU.
1325f29bb8aSDimitry Andric if (foreign_ctxt->isTranslationUnit())
1335f29bb8aSDimitry Andric return sema.getASTContext().getTranslationUnitDecl();
1345f29bb8aSDimitry Andric
1355f29bb8aSDimitry Andric // Recursively find/build the parent DeclContext.
1365f29bb8aSDimitry Andric llvm::Expected<DeclContext *> parent =
1375f29bb8aSDimitry Andric getEqualLocalDeclContext(sema, foreign_ctxt->getParent());
1385f29bb8aSDimitry Andric if (!parent)
1395f29bb8aSDimitry Andric return parent;
1405f29bb8aSDimitry Andric
1415f29bb8aSDimitry Andric // We currently only support building namespaces.
1425f29bb8aSDimitry Andric if (foreign_ctxt->isNamespace()) {
1436f8fc217SDimitry Andric NamedDecl *ns = llvm::cast<NamedDecl>(foreign_ctxt);
1445f29bb8aSDimitry Andric llvm::StringRef ns_name = ns->getName();
1455f29bb8aSDimitry Andric
1465f29bb8aSDimitry Andric auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent);
1475f29bb8aSDimitry Andric for (NamedDecl *named_decl : *lookup_result) {
1485f29bb8aSDimitry Andric if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
1495f29bb8aSDimitry Andric return DC->getPrimaryContext();
1505f29bb8aSDimitry Andric }
1515f29bb8aSDimitry Andric return llvm::make_error<MissingDeclContext>(
1525f29bb8aSDimitry Andric foreign_ctxt,
1535f29bb8aSDimitry Andric "Couldn't find namespace " + ns->getQualifiedNameAsString());
1545f29bb8aSDimitry Andric }
1555f29bb8aSDimitry Andric
1565f29bb8aSDimitry Andric return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
1575f29bb8aSDimitry Andric }
1585f29bb8aSDimitry Andric
1595f29bb8aSDimitry Andric /// Returns true iff tryInstantiateStdTemplate supports instantiating a template
1605f29bb8aSDimitry Andric /// with the given template arguments.
templateArgsAreSupported(ArrayRef<TemplateArgument> a)1615f29bb8aSDimitry Andric static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) {
1625f29bb8aSDimitry Andric for (const TemplateArgument &arg : a) {
1635f29bb8aSDimitry Andric switch (arg.getKind()) {
1645f29bb8aSDimitry Andric case TemplateArgument::Type:
1655f29bb8aSDimitry Andric case TemplateArgument::Integral:
1665f29bb8aSDimitry Andric break;
1675f29bb8aSDimitry Andric default:
1685f29bb8aSDimitry Andric // TemplateArgument kind hasn't been handled yet.
1695f29bb8aSDimitry Andric return false;
1705f29bb8aSDimitry Andric }
1715f29bb8aSDimitry Andric }
1725f29bb8aSDimitry Andric return true;
1735f29bb8aSDimitry Andric }
1745f29bb8aSDimitry Andric
1755f29bb8aSDimitry Andric /// Constructor function for Clang declarations. Ensures that the created
1765f29bb8aSDimitry Andric /// declaration is registered with the ASTImporter.
1775f29bb8aSDimitry Andric template <typename T, typename... Args>
createDecl(ASTImporter & importer,Decl * from_d,Args &&...args)1785f29bb8aSDimitry Andric T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
1795f29bb8aSDimitry Andric T *to_d = T::Create(std::forward<Args>(args)...);
1805f29bb8aSDimitry Andric importer.RegisterImportedDecl(from_d, to_d);
1815f29bb8aSDimitry Andric return to_d;
1825f29bb8aSDimitry Andric }
1835f29bb8aSDimitry Andric
tryInstantiateStdTemplate(Decl * d)184e3b55780SDimitry Andric std::optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
185145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Expressions);
186ead24645SDimitry Andric
1875f29bb8aSDimitry Andric // If we don't have a template to instiantiate, then there is nothing to do.
1885f29bb8aSDimitry Andric auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
1895f29bb8aSDimitry Andric if (!td)
190e3b55780SDimitry Andric return std::nullopt;
1915f29bb8aSDimitry Andric
1925f29bb8aSDimitry Andric // We only care about templates in the std namespace.
1935f29bb8aSDimitry Andric if (!td->getDeclContext()->isStdNamespace())
194e3b55780SDimitry Andric return std::nullopt;
1955f29bb8aSDimitry Andric
196cfca06d7SDimitry Andric // We have a list of supported template names.
197b60736ecSDimitry Andric if (!m_supported_templates.contains(td->getName()))
198e3b55780SDimitry Andric return std::nullopt;
1995f29bb8aSDimitry Andric
2005f29bb8aSDimitry Andric // Early check if we even support instantiating this template. We do this
2015f29bb8aSDimitry Andric // before we import anything into the target AST.
2025f29bb8aSDimitry Andric auto &foreign_args = td->getTemplateInstantiationArgs();
2035f29bb8aSDimitry Andric if (!templateArgsAreSupported(foreign_args.asArray()))
204e3b55780SDimitry Andric return std::nullopt;
2055f29bb8aSDimitry Andric
2065f29bb8aSDimitry Andric // Find the local DeclContext that corresponds to the DeclContext of our
2075f29bb8aSDimitry Andric // decl we want to import.
208ead24645SDimitry Andric llvm::Expected<DeclContext *> to_context =
209ead24645SDimitry Andric getEqualLocalDeclContext(*m_sema, td->getDeclContext());
210ead24645SDimitry Andric if (!to_context) {
211ead24645SDimitry Andric LLDB_LOG_ERROR(log, to_context.takeError(),
212ead24645SDimitry Andric "Got error while searching equal local DeclContext for decl "
213ead24645SDimitry Andric "'{1}':\n{0}",
214ead24645SDimitry Andric td->getName());
215e3b55780SDimitry Andric return std::nullopt;
216ead24645SDimitry Andric }
2175f29bb8aSDimitry Andric
2185f29bb8aSDimitry Andric // Look up the template in our local context.
2195f29bb8aSDimitry Andric std::unique_ptr<LookupResult> lookup =
2205f29bb8aSDimitry Andric emulateLookupInCtxt(*m_sema, td->getName(), *to_context);
2215f29bb8aSDimitry Andric
2225f29bb8aSDimitry Andric ClassTemplateDecl *new_class_template = nullptr;
2235f29bb8aSDimitry Andric for (auto LD : *lookup) {
2245f29bb8aSDimitry Andric if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD)))
2255f29bb8aSDimitry Andric break;
2265f29bb8aSDimitry Andric }
2275f29bb8aSDimitry Andric if (!new_class_template)
228e3b55780SDimitry Andric return std::nullopt;
2295f29bb8aSDimitry Andric
2305f29bb8aSDimitry Andric // Import the foreign template arguments.
2315f29bb8aSDimitry Andric llvm::SmallVector<TemplateArgument, 4> imported_args;
2325f29bb8aSDimitry Andric
2335f29bb8aSDimitry Andric // If this logic is changed, also update templateArgsAreSupported.
2345f29bb8aSDimitry Andric for (const TemplateArgument &arg : foreign_args.asArray()) {
2355f29bb8aSDimitry Andric switch (arg.getKind()) {
2365f29bb8aSDimitry Andric case TemplateArgument::Type: {
2375f29bb8aSDimitry Andric llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
2385f29bb8aSDimitry Andric if (!type) {
2395f29bb8aSDimitry Andric LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
240e3b55780SDimitry Andric return std::nullopt;
2415f29bb8aSDimitry Andric }
2427fa27ce4SDimitry Andric imported_args.push_back(
2437fa27ce4SDimitry Andric TemplateArgument(*type, /*isNullPtr*/ false, arg.getIsDefaulted()));
2445f29bb8aSDimitry Andric break;
2455f29bb8aSDimitry Andric }
2465f29bb8aSDimitry Andric case TemplateArgument::Integral: {
2475f29bb8aSDimitry Andric llvm::APSInt integral = arg.getAsIntegral();
2485f29bb8aSDimitry Andric llvm::Expected<QualType> type =
2495f29bb8aSDimitry Andric m_importer->Import(arg.getIntegralType());
2505f29bb8aSDimitry Andric if (!type) {
2515f29bb8aSDimitry Andric LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
252e3b55780SDimitry Andric return std::nullopt;
2535f29bb8aSDimitry Andric }
2547fa27ce4SDimitry Andric imported_args.push_back(TemplateArgument(d->getASTContext(), integral,
2557fa27ce4SDimitry Andric *type, arg.getIsDefaulted()));
2565f29bb8aSDimitry Andric break;
2575f29bb8aSDimitry Andric }
2585f29bb8aSDimitry Andric default:
2595f29bb8aSDimitry Andric assert(false && "templateArgsAreSupported not updated?");
2605f29bb8aSDimitry Andric }
2615f29bb8aSDimitry Andric }
2625f29bb8aSDimitry Andric
2635f29bb8aSDimitry Andric // Find the class template specialization declaration that
2645f29bb8aSDimitry Andric // corresponds to these arguments.
2655f29bb8aSDimitry Andric void *InsertPos = nullptr;
2665f29bb8aSDimitry Andric ClassTemplateSpecializationDecl *result =
2675f29bb8aSDimitry Andric new_class_template->findSpecialization(imported_args, InsertPos);
2685f29bb8aSDimitry Andric
2695f29bb8aSDimitry Andric if (result) {
2705f29bb8aSDimitry Andric // We found an existing specialization in the module that fits our arguments
2715f29bb8aSDimitry Andric // so we can treat it as the result and register it with the ASTImporter.
2725f29bb8aSDimitry Andric m_importer->RegisterImportedDecl(d, result);
2735f29bb8aSDimitry Andric return result;
2745f29bb8aSDimitry Andric }
2755f29bb8aSDimitry Andric
2765f29bb8aSDimitry Andric // Instantiate the template.
2775f29bb8aSDimitry Andric result = createDecl<ClassTemplateSpecializationDecl>(
2785f29bb8aSDimitry Andric *m_importer, d, m_sema->getASTContext(),
2795f29bb8aSDimitry Andric new_class_template->getTemplatedDecl()->getTagKind(),
2805f29bb8aSDimitry Andric new_class_template->getDeclContext(),
2815f29bb8aSDimitry Andric new_class_template->getTemplatedDecl()->getLocation(),
2825f29bb8aSDimitry Andric new_class_template->getLocation(), new_class_template, imported_args,
2835f29bb8aSDimitry Andric nullptr);
2845f29bb8aSDimitry Andric
2855f29bb8aSDimitry Andric new_class_template->AddSpecialization(result, InsertPos);
2865f29bb8aSDimitry Andric if (new_class_template->isOutOfLine())
2875f29bb8aSDimitry Andric result->setLexicalDeclContext(
2885f29bb8aSDimitry Andric new_class_template->getLexicalDeclContext());
2895f29bb8aSDimitry Andric return result;
2905f29bb8aSDimitry Andric }
2915f29bb8aSDimitry Andric
Import(Decl * d)292e3b55780SDimitry Andric std::optional<Decl *> CxxModuleHandler::Import(Decl *d) {
2935f29bb8aSDimitry Andric if (!isValid())
2945f29bb8aSDimitry Andric return {};
2955f29bb8aSDimitry Andric
2965f29bb8aSDimitry Andric return tryInstantiateStdTemplate(d);
2975f29bb8aSDimitry Andric }
298