diff options
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp')
-rw-r--r-- | source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp | 268 |
1 files changed, 171 insertions, 97 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 8fde41052192b..07ff2e97aac77 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -48,8 +48,10 @@ #include "lldb/lldb-private.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTImporter.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" @@ -178,6 +180,134 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { return ret; } +namespace { +/// This class walks an AST and ensures that all DeclContexts defined inside the +/// current source file are properly complete. +/// +/// This is used to ensure that persistent types defined in the current source +/// file migrate completely to the persistent AST context before they are +/// reused. If that didn't happen, it would be impoossible to complete them +/// because their origin would be gone. +/// +/// The stragtegy used by this class is to check the SourceLocation (to be +/// specific, the FileID) and see if it's the FileID for the current expression. +/// Alternate strategies could include checking whether an ExternalASTMerger, +/// set up to not have the current context as a source, can find an original for +/// the type. +class Completer : public clang::RecursiveASTVisitor<Completer> { +private: + clang::ASTImporter &m_exporter; /// Used to import Decl contents + clang::FileID m_file; /// The file that's going away + llvm::DenseSet<clang::Decl *> m_completed; /// Visited Decls, to avoid cycles + + bool ImportAndCheckCompletable(clang::Decl *decl) { + (void)m_exporter.Import(decl); + if (m_completed.count(decl)) + return false; + if (!llvm::isa<DeclContext>(decl)) + return false; + const clang::SourceLocation loc = decl->getLocation(); + if (!loc.isValid()) + return false; + const clang::FileID file = + m_exporter.getFromContext().getSourceManager().getFileID(loc); + if (file != m_file) + return false; + // We are assuming the Decl was parsed in this very expression, so it should + // not have external storage. + lldbassert(!llvm::cast<DeclContext>(decl)->hasExternalLexicalStorage()); + return true; + } + + void Complete(clang::Decl *decl) { + m_completed.insert(decl); + auto *decl_context = llvm::cast<DeclContext>(decl); + (void)m_exporter.Import(decl); + m_exporter.CompleteDecl(decl); + for (Decl *child : decl_context->decls()) + if (ImportAndCheckCompletable(child)) + Complete(child); + } + + void MaybeComplete(clang::Decl *decl) { + if (ImportAndCheckCompletable(decl)) + Complete(decl); + } + +public: + Completer(clang::ASTImporter &exporter, clang::FileID file) + : m_exporter(exporter), m_file(file) {} + + // Implements the RecursiveASTVisitor's core API. It is called on each Decl + // that the RecursiveASTVisitor encounters, and returns true if the traversal + // should continue. + bool VisitDecl(clang::Decl *decl) { + MaybeComplete(decl); + return true; + } +}; +} + +static void CompleteAllDeclContexts(clang::ASTImporter &exporter, + clang::FileID file, + clang::QualType root) { + clang::QualType canonical_type = root.getCanonicalType(); + if (clang::TagDecl *tag_decl = canonical_type->getAsTagDecl()) { + Completer(exporter, file).TraverseDecl(tag_decl); + } else if (auto interface_type = llvm::dyn_cast<ObjCInterfaceType>( + canonical_type.getTypePtr())) { + Completer(exporter, file).TraverseDecl(interface_type->getDecl()); + } else { + Completer(exporter, file).TraverseType(canonical_type); + } +} + +static clang::QualType ExportAllDeclaredTypes( + clang::ExternalASTMerger &merger, + clang::ASTContext &source, clang::FileManager &source_file_manager, + const clang::ExternalASTMerger::OriginMap &source_origin_map, + clang::FileID file, clang::QualType root) { + clang::ExternalASTMerger::ImporterSource importer_source = + { source, source_file_manager, source_origin_map }; + merger.AddSources(importer_source); + clang::ASTImporter &exporter = merger.ImporterForOrigin(source); + CompleteAllDeclContexts(exporter, file, root); + clang::QualType ret = exporter.Import(root); + merger.RemoveSources(importer_source); + return ret; +} + +TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, + ClangASTContext &source, + TypeFromParser parser_type) { + assert (&target == m_target->GetScratchClangASTContext()); + assert ((TypeSystem*)&source == parser_type.GetTypeSystem()); + assert (source.getASTContext() == m_ast_context); + + if (m_ast_importer_sp) { + return TypeFromUser(m_ast_importer_sp->DeportType( + target.getASTContext(), source.getASTContext(), + parser_type.GetOpaqueQualType()), + &target); + } else if (m_merger_up) { + clang::FileID source_file = + source.getASTContext()->getSourceManager().getFileID( + source.getASTContext()->getTranslationUnitDecl()->getLocation()); + auto scratch_ast_context = static_cast<ClangASTContextForExpressions*>( + m_target->GetScratchClangASTContext()); + clang::QualType exported_type = ExportAllDeclaredTypes( + scratch_ast_context->GetMergerUnchecked(), + *source.getASTContext(), *source.getFileManager(), + m_merger_up->GetOrigins(), + source_file, + clang::QualType::getFromOpaquePtr(parser_type.GetOpaqueQualType())); + return TypeFromUser(exported_type.getAsOpaquePtr(), &target); + } else { + lldbassert(0 && "No mechanism for deporting a type!"); + return TypeFromUser(); + } +} + bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, const ConstString &name, TypeFromParser parser_type, @@ -198,12 +328,8 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - ClangASTContext *context(target->GetScratchClangASTContext()); - - TypeFromUser user_type(m_ast_importer_sp->DeportType( - context->getASTContext(), ast->getASTContext(), - parser_type.GetOpaqueQualType()), - context); + TypeFromUser user_type = + DeportType(*target->GetScratchClangASTContext(), *ast, parser_type); uint32_t offset = m_parser_vars->m_materializer->AddResultVariable( user_type, is_lvalue, m_keep_result_in_memory, m_result_delegate, err); @@ -240,10 +366,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, ClangASTContext *context(target->GetScratchClangASTContext()); - TypeFromUser user_type(m_ast_importer_sp->DeportType( - context->getASTContext(), ast->getASTContext(), - parser_type.GetOpaqueQualType()), - context); + TypeFromUser user_type = DeportType(*context, *ast, parser_type); if (!user_type.GetOpaqueQualType()) { if (log) @@ -688,16 +811,18 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } ClangASTImporter::NamespaceMapSP namespace_map = - m_ast_importer_sp->GetNamespaceMap(namespace_context); + m_ast_importer_sp + ? m_ast_importer_sp->GetNamespaceMap(namespace_context) + : ClangASTImporter::NamespaceMapSP(); + + if (!namespace_map) + return; if (log && log->GetVerbose()) log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)", current_id, static_cast<void *>(namespace_map.get()), (int)namespace_map->size()); - - if (!namespace_map) - return; - + for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end(); i != e; ++i) { @@ -739,16 +864,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( SymbolContextList sc_list; const ConstString name(context.m_decl_name.getAsString().c_str()); - - const char *name_unique_cstr = name.GetCString(); - - if (name_unique_cstr == NULL) - return; - - static ConstString id_name("id"); - static ConstString Class_name("Class"); - - if (name == id_name || name == Class_name) + if (IgnoreName(name, false)) return; // Only look for functions by name out in our symbols if the function @@ -784,8 +900,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( if (!persistent_decl) break; - Decl *parser_persistent_decl = m_ast_importer_sp->CopyDecl( - m_ast_context, scratch_ast_context, persistent_decl); + Decl *parser_persistent_decl = CopyDecl(persistent_decl); if (!parser_persistent_decl) break; @@ -809,7 +924,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } while (0); } - if (name_unique_cstr[0] == '$' && !namespace_decl) { + if (name.GetCString()[0] == '$' && !namespace_decl) { static ConstString g_lldb_class_name("$__lldb_class"); if (name == g_lldb_class_name) { @@ -1041,7 +1156,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( if (ast) { clang::NamespaceDecl *namespace_decl = ClangASTContext::GetUniqueNamespaceDeclaration( - m_ast_context, name_unique_cstr, nullptr); + m_ast_context, name.GetCString(), nullptr); if (namespace_decl) { context.AddNamedDecl(namespace_decl); clang::DeclContext *clang_decl_ctx = @@ -1056,7 +1171,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } // any other $__lldb names should be weeded out now - if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1)) + if (name.GetStringRef().startswith("$__lldb")) return; ExpressionVariableSP pvar_sp( @@ -1329,8 +1444,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( for (clang::NamedDecl *decl : decls_from_modules) { if (llvm::isa<clang::FunctionDecl>(decl)) { clang::NamedDecl *copied_decl = - llvm::cast_or_null<FunctionDecl>(m_ast_importer_sp->CopyDecl( - m_ast_context, &decl->getASTContext(), decl)); + llvm::cast_or_null<FunctionDecl>(CopyDecl(decl)); if (copied_decl) { context.AddNamedDecl(copied_decl); context.m_found.function_with_type_info = true; @@ -1372,9 +1486,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( current_id, name.GetCString()); } - clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl( - m_ast_context, &decl_from_modules->getASTContext(), - decl_from_modules); + clang::Decl *copied_decl = CopyDecl(decl_from_modules); clang::FunctionDecl *copied_function_decl = copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl) : nullptr; @@ -1401,9 +1513,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( current_id, name.GetCString()); } - clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl( - m_ast_context, &decl_from_modules->getASTContext(), - decl_from_modules); + clang::Decl *copied_decl = CopyDecl(decl_from_modules); clang::VarDecl *copied_var_decl = copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) : nullptr; @@ -1430,17 +1540,17 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( // a generic // data symbol, and -- if it is found -- treat it as a variable. Status error; - + const Symbol *data_symbol = m_parser_vars->m_sym_ctx.FindBestGlobalDataSymbol(name, error); - + if (!error.Success()) { const unsigned diag_id = m_ast_context->getDiagnostics().getCustomDiagID( clang::DiagnosticsEngine::Level::Error, "%0"); m_ast_context->getDiagnostics().Report(diag_id) << error.AsCString(); } - + if (data_symbol) { std::string warning("got name from symbols: "); warning.append(name.AsCString()); @@ -1455,49 +1565,6 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } } -// static opaque_compiler_type_t -// MaybePromoteToBlockPointerType -//( -// ASTContext *ast_context, -// opaque_compiler_type_t candidate_type -//) -//{ -// if (!candidate_type) -// return candidate_type; -// -// QualType candidate_qual_type = QualType::getFromOpaquePtr(candidate_type); -// -// const PointerType *candidate_pointer_type = -// dyn_cast<PointerType>(candidate_qual_type); -// -// if (!candidate_pointer_type) -// return candidate_type; -// -// QualType pointee_qual_type = candidate_pointer_type->getPointeeType(); -// -// const RecordType *pointee_record_type = -// dyn_cast<RecordType>(pointee_qual_type); -// -// if (!pointee_record_type) -// return candidate_type; -// -// RecordDecl *pointee_record_decl = pointee_record_type->getDecl(); -// -// if (!pointee_record_decl->isRecord()) -// return candidate_type; -// -// if -// (!pointee_record_decl->getName().startswith(llvm::StringRef("__block_literal_"))) -// return candidate_type; -// -// QualType generic_function_type = -// ast_context->getFunctionNoProtoType(ast_context->UnknownAnyTy); -// QualType block_pointer_type = -// ast_context->getBlockPointerType(generic_function_type); -// -// return block_pointer_type.getAsOpaquePtr(); -//} - bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, lldb_private::Value &var_location, TypeFromUser *user_type, @@ -1537,7 +1604,6 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, "There is no AST context for the current execution context"); return false; } - // var_clang_type = MaybePromoteToBlockPointerType (ast, var_clang_type); DWARFExpression &var_location_expr = var->LocationExpression(); @@ -1762,7 +1828,9 @@ bool ClangExpressionDeclMap::ResolveUnknownTypes() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); - ClangASTContext *scratch_ast_context = target->GetScratchClangASTContext(); + ClangASTContextForExpressions *scratch_ast_context = + static_cast<ClangASTContextForExpressions*>( + target->GetScratchClangASTContext()); for (size_t index = 0, num_entities = m_found_entities.GetSize(); index < num_entities; ++index) { @@ -1793,9 +1861,20 @@ bool ClangExpressionDeclMap::ResolveUnknownTypes() { var_type.getAsOpaquePtr(), ClangASTContext::GetASTContext(&var_decl->getASTContext())); - lldb::opaque_compiler_type_t copied_type = m_ast_importer_sp->CopyType( - scratch_ast_context->getASTContext(), &var_decl->getASTContext(), - var_type.getAsOpaquePtr()); + lldb::opaque_compiler_type_t copied_type = 0; + if (m_ast_importer_sp) { + copied_type = m_ast_importer_sp->CopyType( + scratch_ast_context->getASTContext(), &var_decl->getASTContext(), + var_type.getAsOpaquePtr()); + } else if (HasMerger()) { + copied_type = CopyTypeWithMerger( + var_decl->getASTContext(), + scratch_ast_context->GetMergerUnchecked(), + var_type).getAsOpaquePtr(); + } else { + lldbassert(0 && "No mechanism to copy a resolved unknown type!"); + return false; + } if (!copied_type) { if (log) @@ -1892,8 +1971,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, if (!extern_c) { TypeSystem *type_system = function->GetDeclContext().GetTypeSystem(); - if (ClangASTContext *src_ast = - llvm::dyn_cast<ClangASTContext>(type_system)) { + if (llvm::isa<ClangASTContext>(type_system)) { clang::DeclContext *src_decl_context = (clang::DeclContext *)function->GetDeclContext() .GetOpaqueDeclContext(); @@ -1905,9 +1983,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, src_function_decl->getTemplateSpecializationInfo()->getTemplate(); clang::FunctionTemplateDecl *copied_function_template = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>( - m_ast_importer_sp->CopyDecl(m_ast_context, - src_ast->getASTContext(), - function_template)); + CopyDecl(function_template)); if (copied_function_template) { if (log) { ASTDumper ast_dumper((clang::Decl *)copied_function_template); @@ -1928,9 +2004,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, } else if (src_function_decl) { if (clang::FunctionDecl *copied_function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>( - m_ast_importer_sp->CopyDecl(m_ast_context, - src_ast->getASTContext(), - src_function_decl))) { + CopyDecl(src_function_decl))) { if (log) { ASTDumper ast_dumper((clang::Decl *)copied_function_decl); |