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