summaryrefslogtreecommitdiff
path: root/lldb/source/Symbol/CxxModuleHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Symbol/CxxModuleHandler.cpp')
-rw-r--r--lldb/source/Symbol/CxxModuleHandler.cpp289
1 files changed, 0 insertions, 289 deletions
diff --git a/lldb/source/Symbol/CxxModuleHandler.cpp b/lldb/source/Symbol/CxxModuleHandler.cpp
deleted file mode 100644
index 19e80e5036bc..000000000000
--- a/lldb/source/Symbol/CxxModuleHandler.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-//===-- CxxModuleHandler.cpp ------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/CxxModuleHandler.h"
-
-#include "lldb/Symbol/ClangASTContext.h"
-#include "lldb/Utility/Log.h"
-#include "clang/Sema/Lookup.h"
-#include "llvm/Support/Error.h"
-
-using namespace lldb_private;
-using namespace clang;
-
-CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target)
- : m_importer(&importer),
- m_sema(ClangASTContext::GetASTContext(target)->getSema()) {
-
- std::initializer_list<const char *> supported_names = {
- // containers
- "deque",
- "forward_list",
- "list",
- "queue",
- "stack",
- "vector",
- // pointers
- "shared_ptr",
- "unique_ptr",
- "weak_ptr",
- // utility
- "allocator",
- };
- m_supported_templates.insert(supported_names.begin(), supported_names.end());
-}
-
-/// Builds a list of scopes that point into the given context.
-///
-/// \param sema The sema that will be using the scopes.
-/// \param ctxt The context that the scope should look into.
-/// \param result A list of scopes. The scopes need to be freed by the caller
-/// (except the TUScope which is owned by the sema).
-static void makeScopes(Sema &sema, DeclContext *ctxt,
- std::vector<Scope *> &result) {
- // FIXME: The result should be a list of unique_ptrs, but the TUScope makes
- // this currently impossible as it's owned by the Sema.
-
- if (auto parent = ctxt->getParent()) {
- makeScopes(sema, parent, result);
-
- Scope *scope =
- new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics());
- scope->setEntity(ctxt);
- result.push_back(scope);
- } else
- result.push_back(sema.TUScope);
-}
-
-/// Uses the Sema to look up the given name in the given DeclContext.
-static std::unique_ptr<LookupResult>
-emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) {
- IdentifierInfo &ident = sema.getASTContext().Idents.get(name);
-
- std::unique_ptr<LookupResult> lookup_result;
- lookup_result.reset(new LookupResult(sema, DeclarationName(&ident),
- SourceLocation(),
- Sema::LookupOrdinaryName));
-
- // Usually during parsing we already encountered the scopes we would use. But
- // here don't have these scopes so we have to emulate the behavior of the
- // Sema during parsing.
- std::vector<Scope *> scopes;
- makeScopes(sema, ctxt, scopes);
-
- // Now actually perform the lookup with the sema.
- sema.LookupName(*lookup_result, scopes.back());
-
- // Delete all the allocated scopes beside the translation unit scope (which
- // has depth 0).
- for (Scope *s : scopes)
- if (s->getDepth() != 0)
- delete s;
-
- return lookup_result;
-}
-
-/// Error class for handling problems when finding a certain DeclContext.
-struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
-
- static char ID;
-
- MissingDeclContext(DeclContext *context, std::string error)
- : m_context(context), m_error(error) {}
-
- DeclContext *m_context;
- std::string m_error;
-
- void log(llvm::raw_ostream &OS) const override {
- OS << llvm::formatv("error when reconstructing context of kind {0}:{1}",
- m_context->getDeclKindName(), m_error);
- }
-
- std::error_code convertToErrorCode() const override {
- return llvm::inconvertibleErrorCode();
- }
-};
-
-char MissingDeclContext::ID = 0;
-
-/// Given a foreign decl context, this function finds the equivalent local
-/// decl context in the ASTContext of the given Sema. Potentially deserializes
-/// decls from the 'std' module if necessary.
-static llvm::Expected<DeclContext *>
-getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
-
- // Inline namespaces don't matter for lookups, so let's skip them.
- while (foreign_ctxt && foreign_ctxt->isInlineNamespace())
- foreign_ctxt = foreign_ctxt->getParent();
-
- // If the foreign context is the TU, we just return the local TU.
- if (foreign_ctxt->isTranslationUnit())
- return sema.getASTContext().getTranslationUnitDecl();
-
- // Recursively find/build the parent DeclContext.
- llvm::Expected<DeclContext *> parent =
- getEqualLocalDeclContext(sema, foreign_ctxt->getParent());
- if (!parent)
- return parent;
-
- // We currently only support building namespaces.
- if (foreign_ctxt->isNamespace()) {
- NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt);
- llvm::StringRef ns_name = ns->getName();
-
- auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent);
- for (NamedDecl *named_decl : *lookup_result) {
- if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
- return DC->getPrimaryContext();
- }
- return llvm::make_error<MissingDeclContext>(
- foreign_ctxt,
- "Couldn't find namespace " + ns->getQualifiedNameAsString());
- }
-
- return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
-}
-
-/// Returns true iff tryInstantiateStdTemplate supports instantiating a template
-/// with the given template arguments.
-static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) {
- for (const TemplateArgument &arg : a) {
- switch (arg.getKind()) {
- case TemplateArgument::Type:
- case TemplateArgument::Integral:
- break;
- default:
- // TemplateArgument kind hasn't been handled yet.
- return false;
- }
- }
- return true;
-}
-
-/// Constructor function for Clang declarations. Ensures that the created
-/// declaration is registered with the ASTImporter.
-template <typename T, typename... Args>
-T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
- T *to_d = T::Create(std::forward<Args>(args)...);
- importer.RegisterImportedDecl(from_d, to_d);
- return to_d;
-}
-
-llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
- Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
-
- // If we don't have a template to instiantiate, then there is nothing to do.
- auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
- if (!td)
- return {};
-
- // We only care about templates in the std namespace.
- if (!td->getDeclContext()->isStdNamespace())
- return {};
-
- // We have a whitelist of supported template names.
- if (m_supported_templates.find(td->getName()) == m_supported_templates.end())
- return {};
-
- // Early check if we even support instantiating this template. We do this
- // before we import anything into the target AST.
- auto &foreign_args = td->getTemplateInstantiationArgs();
- if (!templateArgsAreSupported(foreign_args.asArray()))
- return {};
-
- // Find the local DeclContext that corresponds to the DeclContext of our
- // decl we want to import.
- llvm::Expected<DeclContext *> to_context =
- getEqualLocalDeclContext(*m_sema, td->getDeclContext());
- if (!to_context) {
- LLDB_LOG_ERROR(log, to_context.takeError(),
- "Got error while searching equal local DeclContext for decl "
- "'{1}':\n{0}",
- td->getName());
- return {};
- }
-
- // Look up the template in our local context.
- std::unique_ptr<LookupResult> lookup =
- emulateLookupInCtxt(*m_sema, td->getName(), *to_context);
-
- ClassTemplateDecl *new_class_template = nullptr;
- for (auto LD : *lookup) {
- if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD)))
- break;
- }
- if (!new_class_template)
- return {};
-
- // Import the foreign template arguments.
- llvm::SmallVector<TemplateArgument, 4> imported_args;
-
- // If this logic is changed, also update templateArgsAreSupported.
- for (const TemplateArgument &arg : foreign_args.asArray()) {
- switch (arg.getKind()) {
- case TemplateArgument::Type: {
- llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
- if (!type) {
- LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
- return {};
- }
- imported_args.push_back(TemplateArgument(*type));
- break;
- }
- case TemplateArgument::Integral: {
- llvm::APSInt integral = arg.getAsIntegral();
- llvm::Expected<QualType> type =
- m_importer->Import(arg.getIntegralType());
- if (!type) {
- LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
- return {};
- }
- imported_args.push_back(
- TemplateArgument(d->getASTContext(), integral, *type));
- break;
- }
- default:
- assert(false && "templateArgsAreSupported not updated?");
- }
- }
-
- // Find the class template specialization declaration that
- // corresponds to these arguments.
- void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *result =
- new_class_template->findSpecialization(imported_args, InsertPos);
-
- if (result) {
- // We found an existing specialization in the module that fits our arguments
- // so we can treat it as the result and register it with the ASTImporter.
- m_importer->RegisterImportedDecl(d, result);
- return result;
- }
-
- // Instantiate the template.
- result = createDecl<ClassTemplateSpecializationDecl>(
- *m_importer, d, m_sema->getASTContext(),
- new_class_template->getTemplatedDecl()->getTagKind(),
- new_class_template->getDeclContext(),
- new_class_template->getTemplatedDecl()->getLocation(),
- new_class_template->getLocation(), new_class_template, imported_args,
- nullptr);
-
- new_class_template->AddSpecialization(result, InsertPos);
- if (new_class_template->isOutOfLine())
- result->setLexicalDeclContext(
- new_class_template->getLexicalDeclContext());
- return result;
-}
-
-llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) {
- if (!isValid())
- return {};
-
- return tryInstantiateStdTemplate(d);
-}